1
0
mirror of https://github.com/PanJiaChen/vue-element-admin.git synced 2025-08-10 20:39:48 +08:00

fix: #401 Display logics show more fields than they need to be (#402)

* fix: #401 Display logic's showed fields.

* Update evaluator.js

* minor changes.
This commit is contained in:
Edwin Betancourt 2020-03-16 16:19:50 -04:00 committed by GitHub
parent 7fe04ce531
commit 20dfa472b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 181 additions and 157 deletions

View File

@ -15,11 +15,11 @@
:class="classField"
>
<el-form-item
:required="isMandatory()"
:required="isMandatory"
>
<template slot="label">
<operator-comparison
v-if="isAdvancedQuery && isDisplayed"
v-if="isAdvancedQuery"
key="is-field-operator-comparison"
:field-attributes="fieldAttributes"
:field-value="field.value"
@ -31,14 +31,13 @@
:field-value="field.value"
/>
<span v-else key="is-field-name">
{{ isFieldOnly() }}
{{ isFieldOnly }}
</span>
<document-status
v-if="isDocuemntStatus"
:field="fieldAttributes"
/>
<translated
v-if="field.isTranslated && !isAdvancedQuery"
:field-attributes="fieldAttributes"
@ -134,8 +133,8 @@ export default {
inTable: this.inTable,
isAdvancedQuery: this.isAdvancedQuery,
// DOM properties
required: this.isMandatory(),
readonly: this.isReadOnly(),
required: this.isMandatory,
readonly: this.isReadOnly,
displayed: this.isDisplayed,
disabled: !this.field.isActive,
isSelectCreated: this.isSelectCreated
@ -145,7 +144,63 @@ export default {
if (this.isAdvancedQuery) {
return this.field.isShowedFromUser
}
return fieldIsDisplayed(this.field) && (this.isMandatory() || this.field.isShowedFromUser || this.inTable)
return fieldIsDisplayed(this.field) && (this.isMandatory || this.field.isShowedFromUser || this.inTable)
},
isMandatory() {
if (this.isAdvancedQuery) {
return false
}
return this.field.isMandatory || this.field.isMandatoryFromLogic
},
isReadOnly() {
if (this.isAdvancedQuery) {
if (['NULL', 'NOT_NULL'].includes(this.field.operator)) {
return true
}
return false
}
if (!this.field.isActive) {
return true
}
const isUpdateableAllFields = this.field.isReadOnly || this.field.isReadOnlyFromLogic
if (this.field.panelType === 'window') {
if (this.field.isAlwaysUpdateable) {
return false
}
if (this.getterContextProcessing) {
return true
}
if (this.getterContextProcessed) {
return true
}
// TODO: Evaluate record uuid without route.action
// edit mode is diferent to create new
let isWithRecord = this.field.recordUuid !== 'create-new'
if (this.inTable) {
isWithRecord = !this.isEmptyValue(this.field.recordUuid)
}
return (!this.field.isUpdateable && isWithRecord) || (isUpdateableAllFields || this.field.isReadOnlyFromForm)
} else if (this.field.panelType === 'browser') {
if (this.inTable) {
// browser result
return this.field.isReadOnly
}
// query criteria
return this.field.isReadOnlyFromLogic
}
// other type of panels (process/report)
return isUpdateableAllFields
},
isFieldOnly() {
if (this.inTable || this.field.isFieldOnly) {
return undefined
}
return this.field.name
},
isSelectCreated() {
return this.isAdvancedQuery &&
@ -273,64 +328,8 @@ export default {
},
methods: {
showMessage,
isReadOnly() {
if (this.isAdvancedQuery) {
if (['NULL', 'NOT_NULL'].includes(this.field.operator)) {
return true
}
return false
}
if (!this.field.isActive) {
return true
}
const isUpdateableAllFields = this.field.isReadOnly || this.field.isReadOnlyFromLogic
if (this.field.panelType === 'window') {
if (this.field.isAlwaysUpdateable) {
return false
}
if (this.getterContextProcessing) {
return true
}
if (this.getterContextProcessed) {
return true
}
// TODO: Evaluate record uuid without route.action
// edit mode is diferent to create new
let isWithRecord = this.field.recordUuid !== 'create-new'
if (this.inTable) {
isWithRecord = !this.isEmptyValue(this.field.recordUuid)
}
return (!this.field.isUpdateable && isWithRecord) || (isUpdateableAllFields || this.field.isReadOnlyFromForm)
} else if (this.field.panelType === 'browser') {
if (this.inTable) {
// browser result
return this.field.isReadOnly
}
// query criteria
return this.field.isReadOnlyFromLogic
}
// other type of panels (process/report)
return isUpdateableAllFields
},
isMandatory() {
if (this.isAdvancedQuery) {
return false
}
return this.field.isMandatory || this.field.isMandatoryFromLogic
},
isFieldOnly() {
if (this.inTable || this.field.isFieldOnly) {
return undefined
}
return this.field.name
},
focusField() {
if (this.isDisplayed && this.isMandatory() && !this.isReadOnly()) {
if (this.isDisplayed && this.isMandatory && !this.isReadOnly) {
this.$refs[this.field.columnName].activeFocus()
}
}

View File

@ -6,7 +6,7 @@
// - Process & Report: Always save a panel and parameters
// - Smart Browser: Can have a search panel, table panel and process panel
import { isEmptyValue, parsedValueComponent } from '@/utils/ADempiere/valueUtils'
import evaluator, { parseContext } from '@/utils/ADempiere/contextUtils'
import evaluator, { getContext, parseContext } from '@/utils/ADempiere/contextUtils'
import { showMessage } from '@/utils/ADempiere/notification'
import { assignedGroup, fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils'
import router from '@/router'
@ -775,28 +775,27 @@ const panel = {
dependentsList.map(async fieldDependent => {
// isDisplayed Logic
let isDisplayedFromLogic, isMandatoryFromLogic, isReadOnlyFromLogic, defaultValue
if (fieldDependent.displayLogic.trim() !== '') {
if (!isEmptyValue(fieldDependent.displayLogic)) {
isDisplayedFromLogic = evaluator.evaluateLogic({
context: getters,
context: getContext,
parentUuid,
containerUuid,
logic: fieldDependent.displayLogic,
type: 'displayed'
logic: fieldDependent.displayLogic
})
}
// Mandatory Logic
if (fieldDependent.mandatoryLogic.trim() !== '') {
if (!isEmptyValue(fieldDependent.mandatoryLogic)) {
isMandatoryFromLogic = evaluator.evaluateLogic({
context: getters,
context: getContext,
parentUuid,
containerUuid,
logic: fieldDependent.mandatoryLogic
})
}
// Read Only Logic
if (fieldDependent.readOnlyLogic.trim() !== '') {
if (!isEmptyValue(fieldDependent.readOnlyLogic)) {
isReadOnlyFromLogic = evaluator.evaluateLogic({
context: getters,
context: getContext,
parentUuid,
containerUuid,
logic: fieldDependent.readOnlyLogic

View File

@ -129,7 +129,7 @@ export function parseContext({
}
}
if (contextInfo === undefined || contextInfo.length === 0) {
console.info(`No Context for: ${token}`)
// console.info(`No Context for: ${token}`)
isError = true
errorsList.push(token)
} else {

View File

@ -1,6 +1,6 @@
import evaluator from '@/utils/ADempiere/evaluator'
import { isEmptyValue, parsedValueComponent } from '@/utils/ADempiere/valueUtils'
import { getParentFields, getPreference, parseContext } from '@/utils/ADempiere/contextUtils'
import { getContext, getParentFields, getPreference, parseContext } from '@/utils/ADempiere/contextUtils'
import REFERENCES, { FIELD_NOT_SHOWED } from '@/components/ADempiere/Field/references'
import { FIELD_DISPLAY_SIZES, DEFAULT_SIZE } from '@/components/ADempiere/Field/fieldSize'
import language from '@/lang'
@ -26,7 +26,10 @@ export function generateField({
const componentReference = evalutateTypeField(fieldToGenerate.displayType, true)
const referenceType = componentReference.alias[0]
let isDisplayedFromLogic = fieldToGenerate.isDisplayed
let isMandatoryFromLogic = false
let isReadOnlyFromLogic = false
let parentFieldsList = []
let parsedDefaultValue = fieldToGenerate.defaultValue
let parsedDefaultValueTo = fieldToGenerate.defaultValueTo
let operator = 'EQUAL'
@ -116,6 +119,33 @@ export function generateField({
referenceType,
isMandatory: fieldToGenerate.isMandatory
})
parentFieldsList = getParentFields(fieldToGenerate)
// evaluate logics
const setEvaluateLogics = {
parentUuid: moreAttributes.parentUuid,
containerUuid: moreAttributes.containerUuid,
context: getContext
}
if (!isEmptyValue(fieldToGenerate.displayLogic)) {
isDisplayedFromLogic = evaluator.evaluateLogic({
...setEvaluateLogics,
logic: fieldToGenerate.displayLogic
})
}
if (!isEmptyValue(fieldToGenerate.mandatoryLogic)) {
isMandatoryFromLogic = evaluator.evaluateLogic({
...setEvaluateLogics,
logic: fieldToGenerate.mandatoryLogic
})
}
if (!isEmptyValue(fieldToGenerate.readOnlyLogic)) {
isReadOnlyFromLogic = evaluator.evaluateLogic({
...setEvaluateLogics,
logic: fieldToGenerate.readOnlyLogic
})
}
}
const field = {
@ -134,11 +164,11 @@ export function generateField({
parsedDefaultValue,
parsedDefaultValueTo,
// logics to app
isDisplayedFromLogic: fieldToGenerate.isDisplayed,
isReadOnlyFromLogic: false,
isMandatoryFromLogic: false,
isDisplayedFromLogic,
isReadOnlyFromLogic,
isMandatoryFromLogic,
//
parentFieldsList: [],
parentFieldsList,
dependentFieldsList: [],
// TODO: Add support on server
// app attributes
@ -152,31 +182,6 @@ export function generateField({
defaultOperator: operator
}
// evaluate simple logics without context
if (!field.isAdvancedQuery) {
field.parentFieldsList = getParentFields(fieldToGenerate)
if (field.displayLogic.trim() !== '' && !field.displayLogic.includes('@')) {
field.isDisplayedFromLogic = evaluator.evaluateLogic({
type: 'displayed',
logic: field.displayLogic
})
field.isDisplayedFromLogic = Boolean(field.isDisplayedFromLogic)
}
if (field.mandatoryLogic.trim() !== '' && !field.mandatoryLogic.includes('@')) {
field.isMandatoryFromLogic = evaluator.evaluateLogic({
logic: field.mandatoryLogic
})
field.isMandatoryFromLogic = Boolean(field.isMandatoryFromLogic)
}
if (field.readOnlyLogic.trim() !== '' && !field.readOnlyLogic.includes('@')) {
field.isReadOnlyFromLogic = evaluator.evaluateLogic({
logic: field.readOnlyLogic
})
field.isReadOnlyFromLogic = Boolean(field.isReadOnlyFromLogic)
}
}
// Sizes from panel and groups
field.sizeFieldFromType = FIELD_DISPLAY_SIZES.find(item => {
return item.type === field.componentPath
@ -201,9 +206,7 @@ export function generateField({
// hidden field type button
const notShowedField = FIELD_NOT_SHOWED.find(itemField => {
if (field.displayType === itemField.id) {
return true
}
return field.displayType === itemField.id
})
if (notShowedField) {
field.isDisplayedFromLogic = false

View File

@ -15,26 +15,29 @@ class evaluator {
/**
* Evaluate logic's
* @param {string} parentUuid Parent (Window / Process / Smart Browser)
* @param {function} context
* @param {string} logic
* @param {boolean} defaultReturned value to return if logic or context is undefined
*/
static evaluateLogic(objectToEvaluate) {
let defaultUndefined = false
if (objectToEvaluate.type === 'displayed') {
defaultUndefined = true
}
static evaluateLogic({
parentUuid,
containerUuid,
context,
logic,
defaultReturned = false
}) {
// empty logic
if (objectToEvaluate.logic === undefined ||
objectToEvaluate.logic === null ||
objectToEvaluate.logic.trim() === '') {
return defaultUndefined
if (logic === undefined || logic === null || logic.trim() === '') {
return defaultReturned
}
const st = objectToEvaluate.logic.trim().replace('\n', '')
const st = logic.trim().replace('\n', '')
const expr = /(\||&)/
const stList = st.split(expr)
const it = stList.length
if (((it / 2) - ((it + 1) / 2)) === 0) {
console.info(`Logic does not comply with format "<expression> [<logic> <expression>]" --> ${objectToEvaluate.logic}`)
return defaultUndefined
console.info(`Logic does not comply with format "<expression> [<logic> <expression>]" --> ${logic}`)
return defaultReturned
}
let retValue = null
@ -44,23 +47,32 @@ class evaluator {
logOp = element
} else if (retValue === null) {
retValue = evaluator.evaluateLogicTuples({
...objectToEvaluate,
conditional: element
parentUuid,
containerUuid,
context,
logic: element,
defaultReturned
})
} else {
if (logOp.trim() === '&') {
retValue = retValue & evaluator.evaluateLogicTuples({
...objectToEvaluate,
conditional: element
parentUuid,
containerUuid,
context,
logic: element,
defaultReturned
})
} else if (logOp.trim() === '|') {
retValue = retValue | evaluator.evaluateLogicTuples({
...objectToEvaluate,
conditional: element
parentUuid,
containerUuid,
context,
logic: element,
defaultReturned
})
} else {
console.info(`Logic operant '|' or '&' expected --> ${objectToEvaluate.logic}`)
return defaultUndefined
console.info(`Logic operant '|' or '&' expected --> ${logic}`)
return defaultReturned
}
}
})
@ -69,19 +81,23 @@ class evaluator {
/**
* Evaluate Logic Tuples
* @param {object} objectToEvaluate Complete object
* @param {string} parentUuid Complete object
* @param {string} containerUuid Complete object
* @param {function} context
* @param {string} logic If is displayed or not (mandatory and readonly)
* @param {boolean} defaultReturned
* @return {boolean}
*/
static evaluateLogicTuples(objectToEvaluate) {
let _defaultUndefined = false
if (objectToEvaluate.type === 'displayed') {
_defaultUndefined = true
}
const logic = objectToEvaluate.conditional
static evaluateLogicTuples({
parentUuid,
containerUuid,
context,
defaultReturned = false,
logic
}) {
// not context info, not logic
if (logic === undefined) {
return _defaultUndefined
if (logic === undefined || logic === null || logic.trim() === '') {
return defaultReturned
}
/**
@ -97,7 +113,7 @@ class evaluator {
if (!st) {
console.info(`.Logic tuple does not comply with format '@context@=value' where operand could be one of '=!^><' --> ${logic}`)
return _defaultUndefined
return defaultReturned
}
expr = /(<>|<=|==|>=|!=|<|=|>|!|\^)/gm
@ -113,21 +129,26 @@ class evaluator {
first = first.replace(/@/g, '').trim()
isGlobal = first.startsWith('#')
isCountable = first.startsWith('$')
const value = objectToEvaluate.context.getContext({
parentUuid: (isGlobal || isCountable) ? '' : objectToEvaluate.parentUuid,
containerUuid: (isGlobal || isCountable) ? '' : objectToEvaluate.containerUuid,
if (isGlobal || isCountable) {
parentUuid = null
containerUuid = null
}
const value = context({
parentUuid,
containerUuid,
columnName: first
})
// in context exists this column name
if (value === null || value === undefined) {
// console.info(`.The column ${first} not exists in context.`)
return _defaultUndefined
return defaultReturned
}
firstEval = value // replace with it's value
}
if (firstEval === null || firstEval === undefined) {
return _defaultUndefined
return defaultReturned
}
if (typeof firstEval === 'string') {
firstEval = firstEval.replace(/['"]/g, '').trim() // strip ' and "
@ -140,9 +161,9 @@ class evaluator {
let secondEval = second.trim()
if (expr.test(second)) {
second = second.replace(/@/g, ' ').trim() // strip tag
secondEval = objectToEvaluate.context.getContext({
parentUuid: (isGlobal || isCountable) ? null : objectToEvaluate.parentUuid,
containerUuid: (isGlobal || isCountable) ? null : objectToEvaluate.containerUuid,
secondEval = context({
parentUuid,
containerUuid,
columnName: first
}) // replace with it's value
}
@ -161,7 +182,7 @@ class evaluator {
// Logical Comparison
const result = this.evaluateLogicTuple(firstEval, operand, secondEval)
return result
return Boolean(result)
}
/**
@ -172,19 +193,21 @@ class evaluator {
* @return {boolean}
*/
static evaluateLogicTuple(value1, operand, value2) {
// Convert value 1 string value to boolean value
if (value1 === 'Y') {
value1 = true
} else if (value1 === 'N') {
value1 = false
const convertStringToBoolean = (valueToParsed) => {
const valueString = String(valueToParsed).trim()
if (valueString === 'Y') {
return true
} else if (valueString === 'N') {
return false
}
return valueToParsed
}
// Convert value 1 string value to boolean value
value1 = convertStringToBoolean(value1)
// Convert value 2 string value to boolean value
if (value2 === 'Y') {
value2 = true
} else if (value2 === 'N') {
value2 = false
}
value2 = convertStringToBoolean(value2)
let isValueLogic
// TODO: Add '^' operand comparison