1
0
mirror of https://github.com/PanJiaChen/vue-element-admin.git synced 2025-08-10 12:01:57 +08:00

fix: Options fields operator comparison. (#867)

* fix: Options fields operator comparison.

* delete unused code.

* remove consoles.

* fix comment.

* add send client request to search.

* rename to FieldOptions

* separate options fields and component.

* remove unused code.

* remove field/popover dir

* change e-mail

* remane components.

Co-authored-by: EdwinBetanc0urt <EdwinBetanco0urt@outlook.com>
This commit is contained in:
Edwin Betancourt 2021-05-28 18:02:17 -04:00 committed by GitHub
parent 72fb23abda
commit 0f4fedbfa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 805 additions and 642 deletions

View File

@ -1,7 +1,7 @@
<!-- <!--
ADempiere-Vue (Frontend) for ADempiere ERP & CRM Smart Business Solution ADempiere-Vue (Frontend) for ADempiere ERP & CRM Smart Business Solution
Copyright (C) 2017-Present E.R.P. Consultores y Asociados, C.A. Copyright (C) 2017-Present E.R.P. Consultores y Asociados, C.A.
Contributor(s): Edwin Betancourt edwinBetanc0urt@hotmail.com www.erpya.com Contributor(s): Edwin Betancourt EdwinBetanc0urt@outlook.com www.erpya.com
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
@ -17,7 +17,7 @@
--> -->
<template> <template>
<el-popover <el-popover
v-if="(field.columnName === 'DocStatus') && (!isEmptyValue(processOrderUuid))" v-if="(fieldAttributes.columnName === 'DocStatus') && (!isEmptyValue(processOrderUuid))"
placement="right" placement="right"
width="400" width="400"
trigger="click" trigger="click"
@ -37,9 +37,9 @@
</el-select> </el-select>
<el-tag <el-tag
v-if="isEmptyValue(valueActionDocument)" v-if="isEmptyValue(valueActionDocument)"
:type="tagStatus(field.value)" :type="tagStatus(fieldAttributes.value)"
> >
{{ field.displayColumn }} {{ fieldAttributes.displayColumn }}
</el-tag> </el-tag>
<el-tag <el-tag
v-else v-else
@ -47,7 +47,7 @@
> >
{{ labelDocumentActions }} {{ labelDocumentActions }}
</el-tag> </el-tag>
<p v-if="isEmptyValue(valueActionDocument)"> {{ field.description }} </p> <p v-if="isEmptyValue(valueActionDocument)"> {{ fieldAttributes.description }} </p>
<p v-else> {{ descriptionDocumentActions }} </p> <p v-else> {{ descriptionDocumentActions }} </p>
<el-button <el-button
slot="reference" slot="reference"
@ -60,12 +60,14 @@
<script> <script>
export default { export default {
name: 'FieldDocumentStatus', name: 'FieldDocumentStatus',
props: { props: {
field: { fieldAttributes: {
type: Object, type: Object,
required: true required: true
} }
}, },
data() { data() {
return { return {
valueActionDocument: '' valueActionDocument: ''
@ -126,8 +128,8 @@ export default {
}, },
documentActionChange(value) { documentActionChange(value) {
// this.$store.dispatch('notifyFieldChange', { // this.$store.dispatch('notifyFieldChange', {
// parentUuid: this.field.parentUuid, // parentUuid: this.fieldAttributes.parentUuid,
// containerUuid: this.field.containerUuid, // containerUuid: this.fieldAttributes.containerUuid,
// columnName: 'DocAction', // columnName: 'DocAction',
// isSendToServer: true, // isSendToServer: true,
// newValue: value // newValue: value
@ -144,13 +146,13 @@ export default {
recordId: this.$route.params.recordId, recordId: this.$route.params.recordId,
recordUuid: this.$route.query.action, recordUuid: this.$route.query.action,
parametersList: [{ parametersList: [{
columnName: this.field.columnName, columnName: this.fieldAttributes.columnName,
value: this.valueActionDocument value: this.valueActionDocument
}], }],
isActionDocument: true, isActionDocument: true,
parentUuid: this.field.parentUuid, parentUuid: this.fieldAttributes.parentUuid,
panelType: this.field.panelType, panelType: this.fieldAttributes.panelType,
containerUuid: this.field.containerUuid // determinate if get table name and record id (window) or selection (browser) containerUuid: this.fieldAttributes.containerUuid // determinate if get table name and record id (window) or selection (browser)
}) })
this.valueActionDocument = '' this.valueActionDocument = ''
} }

View File

@ -0,0 +1,107 @@
// 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@outlook.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/>.
import language from '@/lang'
export const infoOptionItem = {
name: language.t('field.info'),
enabled: true,
svg: false,
icon: 'el-icon-info',
componentRender: () => import('@/components/ADempiere/Field/contextMenuField/contextInfo')
}
/**
* For operators in advanced query
*/
export const operatorOptionItem = {
name: language.t('operators.operator'),
enabled: true,
svg: false,
icon: 'el-icon-rank',
componentRender: () => import('@/components/ADempiere/Field/FieldOptions/operatorComparison')
}
/**
* For lookup fields with context info
*/
export const zoomInOptionItem = {
name: language.t('table.ProcessActivity.zoomIn'),
enabled: true,
svg: false,
icon: 'el-icon-files',
componentRender: () => import('@/components/ADempiere/Field/contextMenuField/contextInfo')
}
/**
* Only when is translate option
*/
export const translateOptionItem = {
name: language.t('language'),
enabled: true,
svg: true,
icon: 'language',
componentRender: () => import('@/components/ADempiere/Field/contextMenuField/translated')
}
/**
* Displayed calculator option in numeric field
*/
export const calculatorOptionItem = {
name: language.t('field.calculator'),
enabled: true,
svg: false,
icon: 'el-icon-s-operation',
componentRender: () => import('@/components/ADempiere/Field/contextMenuField/calculator')
}
export const preferenceOptionItem = {
name: language.t('field.preference'),
enabled: true,
svg: false,
icon: 'el-icon-notebook-2',
componentRender: () => import('@/components/ADempiere/Field/FieldOptions/preference')
}
export const logsOptionItem = {
name: language.t('field.logsField'),
enabled: true,
svg: true,
icon: 'tree-table',
componentRender: () => import('@/components/ADempiere/Field/contextMenuField/changeLogs')
}
/**
* For document status field to workflow
*/
export const documentStatusOptionItem = {
name: language.t('window.documentStatus'),
enabled: true,
svg: false,
icon: 'el-icon-set-up',
componentRender: () => import('@/components/ADempiere/Field/FieldOptions/documentStatus')
}
export const optionsListStandad = [
infoOptionItem,
preferenceOptionItem,
logsOptionItem
]
export const optionsListAdvancedQuery = [
infoOptionItem,
operatorOptionItem
]

View File

@ -0,0 +1,516 @@
<!--
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>

View File

@ -0,0 +1,134 @@
<!--
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@outlook.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 class="operator-comparison">
<span class="custom-tittle-popover">
{{ $t('operators.compareSearch') }}:
</span>
<br>
<el-select
v-model="currentOperator"
@change="changeOperator"
>
<el-option
v-for="(itemOperator, key) in operatorsList"
:key="key"
:value="itemOperator"
:label="$t('operators.' + itemOperator)"
/>
</el-select>
</div>
</template>
<script>
import { computed, defineComponent, ref } from '@vue/composition-api'
export default defineComponent({
name: 'FieldOperatorComparison',
props: {
fieldAttributes: {
type: Object,
required: true
}
},
setup(props, { root }) {
const operatorsList = ref(props.fieldAttributes.operatorsList)
const currentOperator = computed({
get() {
const { columnName, containerUuid } = props.fieldAttributes
const { operator } = root.$store.getters.getFieldFromColumnName({
containerUuid,
columnName
})
return operator
},
set(newValue) {
const { columnName, containerUuid } = props.fieldAttributes
root.$store.dispatch('changeFieldAttribure', {
containerUuid,
columnName,
attributeName: 'operator',
attributeValue: newValue
})
}
})
const fieldValue = computed(() => {
const { columnName, containerUuid, parentUuid } = props.fieldAttributes
// main panel values
return root.$store.getters.getValueOfField({
parentUuid,
containerUuid,
columnName
})
})
/**
* @param {mixed} value, main value in component
*/
const handleChange = (value) => {
const { columnName, containerUuid } = props.fieldAttributes
root.$store.dispatch('notifyFieldChange', {
containerUuid,
field: props.fieldAttributes,
columnName,
newValue: value
})
}
/**
* @param {string} operatorValue
*/
const changeOperator = (operatorValue) => {
const value = fieldValue.value
if (!root.isEmptyValue(value) ||
['NULL', 'NOT_NULL'].includes(operatorValue)) {
handleChange(value)
}
}
return {
currentOperator,
operatorsList,
changeOperator
}
}
})
</script>
<style scoped lang="scss">
.custom-tittle-popover {
font-size: 14px;
font-weight: bold;
float: left;
}
.operator-comparison {
margin: 10px;
padding: 10px;
}
</style>

View File

@ -25,10 +25,8 @@
<span> <span>
{{ $t('components.preference.title') }} {{ $t('components.preference.title') }}
<b> <b>
{{ sourceField.name }} {{ fieldAttributes.name }}
{{ {{ fieldValue }}
fieldValue
}}
</b> </b>
</span> </span>
</div> </div>
@ -44,7 +42,7 @@
> >
<el-form-item> <el-form-item>
<p slot="label"> <p slot="label">
{{ sourceField.name }}: {{ fieldValue }} {{ fieldAttributes.name }}: {{ fieldValue }}
</p> </p>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -116,7 +114,7 @@ export default {
name: 'Preference', name: 'Preference',
mixins: [formMixin], mixins: [formMixin],
props: { props: {
sourceField: { fieldAttributes: {
type: [Object], type: [Object],
required: true, required: true,
default: null default: null
@ -194,7 +192,7 @@ export default {
this.setFieldsList() this.setFieldsList()
} }
if (!this.isEmptyValue(preferenceValue)) { if (!this.isEmptyValue(preferenceValue)) {
if ((typeof preferenceValue !== 'string') && (this.sourceField.componentPath !== 'FieldYesNo')) { if ((typeof preferenceValue !== 'string') && (this.fieldAttributes.componentPath !== 'FieldYesNo')) {
this.code = preferenceValue this.code = preferenceValue
} else { } else {
this.code = preferenceValue this.code = preferenceValue
@ -230,8 +228,8 @@ export default {
const isForCurrentOrganization = this.metadataList.find(field => field.columnName === 'AD_Org_ID').value const isForCurrentOrganization = this.metadataList.find(field => field.columnName === 'AD_Org_ID').value
const isForCurrentContainer = this.metadataList.find(field => field.columnName === 'AD_Window_ID').value const isForCurrentContainer = this.metadataList.find(field => field.columnName === 'AD_Window_ID').value
deletePreference({ deletePreference({
parentUuid: this.sourceField.parentUuid, parentUuid: this.fieldAttributes.parentUuid,
attribute: this.sourceField.columnName, attribute: this.fieldAttributes.columnName,
isForCurrentUser, isForCurrentUser,
isForCurrentClient, isForCurrentClient,
isForCurrentOrganization, isForCurrentOrganization,
@ -282,8 +280,8 @@ export default {
const isForCurrentContainer = this.metadataList.find(field => field.columnName === 'AD_Window_ID').value const isForCurrentContainer = this.metadataList.find(field => field.columnName === 'AD_Window_ID').value
// //
setPreference({ setPreference({
parentUuid: this.sourceField.parentUuid, parentUuid: this.fieldAttributes.parentUuid,
attribute: this.sourceField.columnName, attribute: this.fieldAttributes.columnName,
value: this.fieldValue, value: this.fieldValue,
isForCurrentUser, isForCurrentUser,
isForCurrentClient, isForCurrentClient,

View File

@ -33,171 +33,11 @@
> >
<el-form-item> <el-form-item>
<template slot="label"> <template slot="label">
<el-dropdown <field-options
v-if="isMobile" :metadata="fieldAttributes"
size="mini"
:hide-on-click="true"
trigger="click"
:style="isMobile ? 'text-overflow: ellipsis; white-space: nowrap; overflow: hidden; width:'+labelStyle+'%' : ''"
@command="handleCommand"
@click="false"
>
<div :style="isMobile ? 'display: flex;width: auto;' : 'display: block;'">
<span :style="isMandatory && isEmptyValue(valueField) ? 'border: aqua; color: #f34b4b' : 'border: aqua;'">
<span key="is-field-name">
{{ field.name }}
</span>
</span>
</div>
<el-dropdown-menu slot="dropdown">
<template
v-for="(option, key) in optionField"
>
<el-dropdown-item
v-if="option.enabled"
:key="key"
:command="option"
:divided="true"
>
<el-popover
v-if="!isMobile"
placement="top"
trigger="click"
style="padding: 0px;"
>
<component
:is="optionFieldFComponentRender"
v-if="visibleForDesktop"
:field-attributes="contextMenuField.fieldAttributes"
:source-field="contextMenuField.fieldAttributes"
:field-value="contextMenuField.valueField"
/>
<el-button slot="reference" type="text" style="color: #606266;">
<div class="contents">
<div v-if="!option.svg" style="margin-right: 5%;padding-top: 3%;">
<i :class="option.icon" style="font-weight: bolder;" />
</div>
<div v-else style="margin-right: 5%">
<svg-icon :icon-class="option.icon" style="margin-right: 5px;" />
</div>
<div>
<span class="contents">
<b class="label">
{{ option.name }}
</b>
</span>
</div>
</div>
</el-button>
</el-popover>
<div v-if="isMobile" class="contents">
<div v-if="!option.svg" style="margin-right: 5%;padding-top: 3%;">
<i :class="option.icon" style="font-weight: bolder;" />
</div>
<div v-else style="margin-right: 5%">
<svg-icon :icon-class="option.icon" style="margin-right: 5px;" />
</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="field.panelType !== 'form' && !isMobile" class="el-menu-demo" mode="horizontal" :unique-opened="true" style="z-index: 0" :menu-trigger="triggerMenu" @open="handleOpen" @close="handleClose" @select="handleSelect">
<el-submenu index="menu">
<template slot="title">
<div :style="isMobile ? 'display: flex;width: auto;' : 'display: block;'">
<span :style="isMandatory && isEmptyValue(valueField) ? 'border: aqua; color: #f34b4b' : 'border: aqua;'">
<span key="is-field-name">
{{ field.name }}
</span>
</span>
</div>
</template>
<el-menu-item
v-for="(option, key) in listOption"
:key="key"
:index="option.name"
>
<el-popover
v-if="!isMobile"
placement="top"
width="400"
trigger="click"
style="padding: 0px;"
@hide="closePopover"
>
<component
:is="optionFieldFComponentRender"
v-if="visibleForDesktop && showPanelFieldOption"
:field-attributes="contextMenuField.fieldAttributes"
:source-field="contextMenuField.fieldAttributes"
:field-value="contextMenuField.valueField"
/>
<el-button slot="reference" type="text" style="color: #606266;">
<div class="contents">
<div
v-if="!option.svg"
style="margin-right: 5%;padding-top: 3%;"
>
<i :class="option.icon" style="font-weight: bolder;" />
</div>
<div v-else style="margin-right: 5%;; padding-left: 2%;">
<svg-icon :icon-class="option.icon" style="margin-right: 5px;" />
</div>
<div>
<span class="contents">
<b class="label">
{{ option.name }}
</b>
</span>
</div>
</div>
</el-button>
</el-popover>
<div v-if="false" class="contents">
<div v-if="!option.svg" style="margin-right: 5%;padding-top: 3%;">
<i :class="option.icon" style="font-weight: bolder;" />
</div>
<div v-else style="margin-right: 5%">
<svg-icon :icon-class="option.icon" style="margin-right: 5px;" />
</div>
<div>
<span class="contents">
<b class="label">
{{ option.name }}
</b>
</span>
</div>
</div>
</el-menu-item>
</el-submenu>
</el-menu>
<span v-else>
{{ field.name }}
</span>
</template>
<el-popover
v-if="openOptionField && !isEmptyValue(optionColumnName) && (optionColumnName === field.columnName) && showPopoverPath"
v-model="openOptionField"
placement="top-start"
width="400"
trigger="click"
>
<component
:is="optionFieldFComponentRender"
:field-attributes="fieldAttributes"
:source-field="fieldAttributes"
:field-value="valueField"
/> />
<el-button slot="reference" type="text" :disabled="true" @click="openOptionField = !openOptionField" /> </template>
</el-popover>
<component <component
:is="componentRender" :is="componentRender"
:ref="field.columnName" :ref="field.columnName"
@ -219,11 +59,9 @@
</template> </template>
<script> <script>
import documentStatus from '@/components/ADempiere/Field/popover/documentStatus'
import operatorComparison from '@/components/ADempiere/Field/popover/operatorComparison'
import { DEFAULT_SIZE } from '@/utils/ADempiere/references' import { DEFAULT_SIZE } from '@/utils/ADempiere/references'
import { evalutateTypeField, fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils' import { evalutateTypeField, fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils'
import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js' import FieldOptions from '@/components/ADempiere/Field/FieldOptions'
/** /**
* This is the base component for linking the components according to the * This is the base component for linking the components according to the
@ -231,10 +69,11 @@ import { recursiveTreeSearch } from '@/utils/ADempiere/valueUtils.js'
*/ */
export default { export default {
name: 'FieldDefinition', name: 'FieldDefinition',
components: { components: {
documentStatus, FieldOptions
operatorComparison
}, },
props: { props: {
// receives the property that is an object with all the attributes // receives the property that is an object with all the attributes
metadataField: { metadataField: {
@ -260,58 +99,14 @@ export default {
}, },
data() { data() {
return { return {
field: {}, field: {}
visibleForDesktop: false,
triggerMenu: 'click',
showPopoverPath: false,
optionColumnName: this.$route.query.fieldColumnName
} }
}, },
computed: { computed: {
// load the component that is indicated in the attributes of received property
showPanelFieldOption() {
return this.$store.state.contextMenu.isShowOptionField
},
labelStyle() {
if (this.field.name.length >= 25) {
return '35'
} else if (this.field.name.length >= 20) {
return '50'
}
return '110'
},
isMobile() { isMobile() {
return this.$store.state.app.device === 'mobile' return this.$store.state.app.device === 'mobile'
}, },
contextMenuField() { // load the component that is indicated in the attributes of received property
return this.$store.getters.getFieldContextMenu
},
panelContextMenu() {
return this.$store.state.contextMenu.isShowRightPanel
},
optionFieldFComponentRender() {
let component
const option = this.optionField.find(option => this.$route.query.typeAction === option.name)
const nameComponent = this.isEmptyValue(option) ? this.contextMenuField.name : this.$route.query.typeAction
switch (nameComponent) {
case this.$t('field.info'):
component = () => import('@/components/ADempiere/Field/contextMenuField/contextInfo')
break
case this.$t('language'):
component = () => import('@/components/ADempiere/Field/contextMenuField/translated/index')
break
case this.$t('field.calculator'):
component = () => import('@/components/ADempiere/Field/contextMenuField/calculator')
break
case this.$t('field.preference'):
component = () => import('@/components/ADempiere/Field/contextMenuField/preference/index')
break
case this.$t('field.logsField'):
component = () => import('@/components/ADempiere/Field/contextMenuField/changeLogs/index')
break
}
return component
},
componentRender() { componentRender() {
if (this.isEmptyValue(this.field.componentPath || !this.field.isSupported)) { if (this.isEmptyValue(this.field.componentPath || !this.field.isSupported)) {
return () => import('@/components/ADempiere/Field/FieldText') return () => import('@/components/ADempiere/Field/FieldText')
@ -371,6 +166,7 @@ export default {
return { return {
...this.field, ...this.field,
inTable: this.inTable, inTable: this.inTable,
isPanelWindow: this.isPanelWindow,
isAdvancedQuery: this.isAdvancedQuery, isAdvancedQuery: this.isAdvancedQuery,
// DOM properties // DOM properties
required: this.isMandatory, required: this.isMandatory,
@ -541,137 +337,14 @@ export default {
return sizeField return sizeField
} }
return sizeField return sizeField
},
processOrderUuid() {
return this.$store.getters.getOrders
},
isDocuemntStatus() {
if (this.isPanelWindow && !this.isAdvancedQuery) {
if (this.field.columnName === 'DocStatus' && !this.isEmptyValue(this.processOrderUuid)) {
return true
}
}
return false
},
isContextInfo() {
if (!this.isPanelWindow) {
return false
}
return Boolean(this.field.contextInfo && this.field.contextInfo.isActive) ||
Boolean(this.field.reference && this.field.reference.zoomWindows.length)
},
optionField() {
return [
{
name: this.$t('field.info'),
enabled: true,
fieldAttributes: this.fieldAttributes,
svg: false,
icon: 'el-icon-info'
},
{
name: this.$t('table.ProcessActivity.zoomIn'),
enabled: this.isContextInfo,
fieldAttributes: this.fieldAttributes,
svg: false,
icon: 'el-icon-files'
},
{
name: this.$t('language'),
enabled: this.field.isTranslatedField,
fieldAttributes: this.fieldAttributes,
svg: true,
icon: 'language'
},
{
name: this.$t('field.calculator'),
enabled: this.field.isNumericField,
fieldAttributes: this.fieldAttributes,
recordDataFields: this.recordDataFields,
valueField: this.valueField,
svg: false,
icon: 'el-icon-s-operation'
},
{
name: this.$t('field.preference'),
enabled: true,
fieldAttributes: this.fieldAttributes,
valueField: this.valueField,
svg: false,
icon: 'el-icon-notebook-2'
},
{
name: this.$t('field.logsField'),
enabled: true,
fieldAttributes: this.fieldAttributes,
valueField: this.valueField,
svg: true,
icon: 'tree-table'
}
]
},
listOption() {
return this.optionField.filter(option => option.enabled)
},
permissionRoutes() {
return this.$store.getters.permission_routes
},
valueField() {
return this.$store.getters.getValueOfField({
parentUuid: this.fieldAttributes.parentUuid,
containerUuid: this.fieldAttributes.containerUuid,
columnName: this.fieldAttributes.columnName
})
},
openOptionField: {
get() {
const option = this.optionField.find(option => this.$route.query.typeAction === option.name)
if (!this.isEmptyValue(this.$route.query) && option) {
return true
}
return false
},
set(value) {
if (!value) {
this.showPopoverPath = false
this.$router.push({
name: this.$route.name,
query: {
...this.$route.query,
typeAction: '',
fieldColumnName: ''
}
}, () => {})
}
}
} }
}, },
watch: { watch: {
panelContextMenu(value) {
this.visibleForDesktop = false
},
metadataField(value) { metadataField(value) {
this.field = value this.field = value
},
openOptionField(value) {
if (!value) {
this.showPopoverPath = false
}
} }
}, },
created() { created() {
this.timeOut = setTimeout(() => {
if (this.isMobile && this.optionColumnName === this.field.columnName) {
this.$store.commit('changeShowRigthPanel', true)
this.$store.dispatch('setOptionField', {
fieldAttributes: this.fieldAttributes,
name: this.$route.query.typeAction,
valueField: this.valueField
})
} else {
this.showPopoverPath = true
}
}, 2000)
// assined field with prop // assined field with prop
this.field = this.metadataField this.field = this.metadataField
if (this.field.isCustomField && !this.field.componentPath) { if (this.field.isCustomField && !this.field.componentPath) {
@ -693,189 +366,16 @@ export default {
} }
}, },
methods: { methods: {
recursiveTreeSearch,
closePopover() {
this.$router.push({
name: this.$route.name,
query: {
...this.$route.query,
typeAction: '',
fieldColumnName: ''
}
}, () => {})
},
handleOpen(key, keyPath) {
this.triggerMenu = 'hover'
},
handleClose(key, keyPath) {
this.triggerMenu = 'click'
},
handleSelect(key, keyPath) {
const option = this.listOption.find(option => option.name === key)
if (option.name === this.$t('table.ProcessActivity.zoomIn')) {
this.redirect({ window: option.fieldAttributes.reference.zoomWindows[0] })
return
}
if (this.isMobile) {
this.$store.commit('changeShowRigthPanel', true)
} else {
this.$store.commit('changeShowOptionField', true)
this.visibleForDesktop = true
this.$router.push({
name: this.$route.name,
query: {
...this.$route.query,
typeAction: key,
fieldColumnName: this.field.columnName
}
}, () => {})
}
this.$store.commit('changeShowPopoverField', true)
this.$store.dispatch('setOptionField', option)
this.triggerMenu = 'hover'
},
focusField() { focusField() {
if (this.field.handleRequestFocus || (this.field.displayed && !this.field.readonly)) { if (this.field.handleRequestFocus || (this.field.displayed && !this.field.readonly)) {
this.$refs[this.field.columnName].requestFocus() this.$refs[this.field.columnName].requestFocus()
} }
},
handleCommand(command) {
this.$store.commit('setRecordAccess', false)
if (command.name === this.$t('table.ProcessActivity.zoomIn')) {
this.redirect({ window: command.fieldAttributes.reference.zoomWindows[0] })
return
}
if (this.isMobile) {
this.$store.commit('changeShowRigthPanel', true)
} else {
this.visibleForDesktop = true
}
this.$store.commit('changeShowPopoverField', true)
this.$store.dispatch('setOptionField', command)
},
redirect({ window }) {
const viewSearch = recursiveTreeSearch({
treeData: this.permissionRoutes,
attributeValue: window.uuid,
attributeName: 'meta',
secondAttribute: 'uuid',
attributeChilds: 'children'
})
if (viewSearch) {
this.$router.push({
name: viewSearch.name,
query: {
action: 'advancedQuery',
tabParent: 0,
[this.fieldAttributes.columnName]: this.value
}
}, () => {})
} else {
this.$message({
type: 'error',
showClose: true,
message: this.$t('notifications.noRoleAccess')
})
}
} }
} }
} }
</script> </script>
<style scoped>
.el-form--label-top .el-form-item__label {
padding-bottom: 0px !important;
display: block;
}
</style>
<style>
.el-popper {
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-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>
<style lang="scss"> <style lang="scss">
.el-popover {
position: fixed;
}
.custom-tittle-popover {
font-size: 14px;
font-weight: bold;
float: left;
}
/** /**
* Separation between elements (item) of the form * Separation between elements (item) of the form
*/ */
@ -898,7 +398,9 @@ export default {
margin-right: 0px; margin-right: 0px;
} }
/* Global Styles */ /**
* Min height all text area, not into table
*/
.el-textarea__inner:not(.in-table) { .el-textarea__inner:not(.in-table) {
min-height: 36px !important; min-height: 36px !important;
/* /*

View File

@ -1,103 +0,0 @@
<!--
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@hotmail.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>
<span v-if="fieldAttributes.isComparisonField">
<el-popover
ref="operatorComarison"
placement="top"
width="230"
trigger="click"
>
<span class="custom-tittle-popover">
{{ $t('operators.operator') }}:
</span>
<el-select
v-model="value"
@change="changeOperator"
>
<el-option
v-for="(item, key) in fieldAttributes.operatorsList"
:key="key"
:value="item"
:label="$t('operators.' + item)"
/>
</el-select>
</el-popover>
<span v-popover:operatorComarison>
{{ fieldAttributes.name }}
</span>
</span>
</template>
<script>
export default {
name: 'FieldOperatorComparison',
props: {
fieldAttributes: {
type: Object,
required: true
}
},
data() {
return {
value: this.fieldAttributes.operator
}
},
watch: {
'fieldAttributes.operator'(newValue) {
this.value = newValue
if (!this.isEmptyValue(this.fieldAttributes.value) ||
['NULL', 'NOT_NULL'].includes(this.fieldAttributes.operator)) {
this.handleChange(this.fieldAttributes.value)
}
}
},
methods: {
changeOperator(operatorValue) {
this.$store.dispatch('changeFieldAttribure', {
containerUuid: this.fieldAttributes.containerUuid,
columnName: this.fieldAttributes.columnName,
attributeName: 'operator',
attributeValue: operatorValue
})
},
/**
* @param {mixed} value, main value in component
* @param {mixed} valueTo, used in end value in range
* @param {string} label, or displayColumn to show in select
*/
handleChange(value) {
// const sendParameters = {
// parentUuid: this.fieldAttributes.parentUuid,
// containerUuid: this.fieldAttributes.containerUuid,
// field: this.fieldAttributes,
// panelType: this.fieldAttributes.panelType,
// columnName: this.fieldAttributes.columnName,
// newValue: value === 'NotSend' ? this.value : value,
// isAdvancedQuery: true,
// isSendToServer: !(value === 'NotSend'),
// isSendCallout: false
// }
// this.$store.dispatch('notifyFieldChange', {
// ...sendParameters,
// isChangedOldValue: this.fieldAttributes.componentPath === 'FieldYesNo' && Boolean(value === 'NotSend')
// })
}
}
}
</script>

View File

@ -321,6 +321,7 @@ export default {
addNote: 'Add Note' addNote: 'Add Note'
} }
}, },
documentStatus: 'Document Status',
callout: { callout: {
error: 'Error In Callout' error: 'Error In Callout'
} }
@ -380,6 +381,7 @@ export default {
sequence: 'Sequence' sequence: 'Sequence'
}, },
operators: { operators: {
compareSearch: 'Compare the Search',
operator: 'Comparison operator', operator: 'Comparison operator',
EQUAL: 'Equal to "="', EQUAL: 'Equal to "="',
NOT_EQUAL: 'Not equal to "<>"', NOT_EQUAL: 'Not equal to "<>"',

View File

@ -297,6 +297,7 @@ export default {
addNote: 'Agregar Nota' addNote: 'Agregar Nota'
} }
}, },
documentStatus: 'Estatus del Documento',
callout: { callout: {
error: 'Error En Callout' error: 'Error En Callout'
} }
@ -356,6 +357,7 @@ export default {
sequence: 'Secuencia' sequence: 'Secuencia'
}, },
operators: { operators: {
compareSearch: 'Comparar la Búsqueda',
operator: 'Operador de comparación', operator: 'Operador de comparación',
EQUAL: 'Igual a "="', EQUAL: 'Igual a "="',
NOT_EQUAL: 'Diferente a "<>"', NOT_EQUAL: 'Diferente a "<>"',

View File

@ -1,6 +1,6 @@
// ADempiere-Vue (Frontend) for ADempiere ERP & CRM Smart Business Solution // ADempiere-Vue (Frontend) for ADempiere ERP & CRM Smart Business Solution
// Copyright (C) 2017-Present E.R.P. Consultores y Asociados, C.A. // Copyright (C) 2017-Present E.R.P. Consultores y Asociados, C.A.
// Contributor(s): Edwin Betancourt edwinBetanc0urt@hotmail.com www.erpya.com // Contributor(s): Edwin Betancourt EdwinBetanc0urt@outlook.com www.erpya.com
// This program is free software: you can redistribute it and/or modify // 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 // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
@ -104,16 +104,19 @@ export default {
component = () => import('@/components/ADempiere/Field/contextMenuField/contextInfo') component = () => import('@/components/ADempiere/Field/contextMenuField/contextInfo')
break break
case this.$t('language'): case this.$t('language'):
component = () => import('@/components/ADempiere/Field/contextMenuField/translated/index') component = () => import('@/components/ADempiere/Field/contextMenuField/translated')
break break
case this.$t('field.calculator'): case this.$t('field.calculator'):
component = () => import('@/components/ADempiere/Field/contextMenuField/calculator') component = () => import('@/components/ADempiere/Field/contextMenuField/calculator')
break break
case this.$t('field.preference'): case this.$t('field.preference'):
component = () => import('@/components/ADempiere/Field/contextMenuField/preference/index') component = () => import('@/components/ADempiere/Field/FieldOptions/preference')
break break
case this.$t('field.logsField'): case this.$t('field.logsField'):
component = () => import('@/components/ADempiere/Field/contextMenuField/changeLogs/index') component = () => import('@/components/ADempiere/Field/contextMenuField/changeLogs')
break
case this.$t('operators.operator'):
component = () => import('@/components/ADempiere/Field/FieldOptions/operatorComparison')
break break
} }
return component return component