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

Add calculator component to numeric references (#349)

* add calc component

* change display values to top

* Update version for gRPC data client

* redefine styles and enter key press event

* Revert "Merge branch 'develop' of https://github.com/erpcya/adempiere-vue into develop"

This reverts commit eaa9477d2b52e87962b7610fda7944fc944460a6.

* Revert "Merge branch 'develop' of https://github.com/erpcya/adempiere-vue into develop"

This reverts commit eaa9477d2b52e87962b7610fda7944fc944460a6.

* add mathematical operation directly from field

* add value to math operation in real time

* minor changes

* minor changes

* validate input values

* redefine logics

Co-authored-by: Edwin Betancourt <EdwinBetanc0urt@hotmail.com>
Co-authored-by: Yamel Senih <ysenih@erpya.com>
This commit is contained in:
Leonel Matos 2020-02-28 02:21:51 -04:00 committed by GitHub
parent 5bd42f1961
commit 618a24d22f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 447 additions and 54 deletions

View File

@ -1,17 +1,23 @@
<template>
<el-input-number
:ref="metadata.columnName"
v-model="value"
type="number"
:min="minValue"
:max="maxValue"
:placeholder="metadata.help"
:disabled="isDisabled"
:precision="precision"
controls-position="right"
:class="'display-type-' + cssClass"
@change="preHandleChange"
/>
<el-tooltip v-model="isShowed" :manual="true" :content="valueToDisplay" placement="top" effect="light">
<el-input-number
:ref="metadata.columnName"
v-model="value"
v-shortkey="['enter']"
type="number"
:min="minValue"
:max="maxValue"
:placeholder="metadata.help"
:disabled="isDisabled"
:precision="precision"
controls-position="right"
:class="'display-type-' + cssClass"
@change="preHandleChange"
@shortkey.native="changeValue"
@blur="changeValue"
@keydown.native="calculateValue"
/>
</el-tooltip>
</template>
<script>
@ -30,7 +36,11 @@ export default {
value = this.validateValue(value)
return {
value: value,
showControls: true
showControls: true,
operation: '',
expression: /[^\d\/.()%\*\+\-]/gim,
valueToDisplay: '',
isShowed: false
}
},
computed: {
@ -78,6 +88,33 @@ export default {
return undefined
}
return Number(value)
},
calculateValue(event) {
const result = this.calculationValue(this.value, event)
if (!this.isEmptyValue(result)) {
this.valueToDisplay = result
this.isShowed = true
} else {
this.valueToDisplay = '...'
this.isShowed = true
}
},
changeValue() {
const result = this.validateValue(this.valueToDisplay)
this.$store.dispatch('notifyFieldChange', {
isAdvancedQuery: this.metadata.isAdvancedQuery,
panelType: this.metadata.panelType,
parentUuid: this.metadata.parentUuid,
containerUuid: this.metadata.containerUuid,
columnName: this.metadata.columnName,
newValue: result,
field: this.metadata,
isChangedOldValue: true
})
.finally(() => {
this.clearVariables()
this.isShowed = false
})
}
}
}

View File

@ -18,13 +18,13 @@
:required="isMandatory()"
>
<template slot="label">
<field-operator-comparison
<operator-comparison
v-if="isAdvancedQuery && isDisplayed"
key="is-field-operator-comparison"
:field-attributes="fieldAttributes"
:field-value="field.value"
/>
<field-context-info
<context-info
v-else-if="isContextInfo"
key="is-field-context-info"
:field-attributes="fieldAttributes"
@ -34,16 +34,21 @@
{{ isFieldOnly() }}
</span>
<field-document-status
<document-status
v-if="isDocuemntStatus"
:field="fieldAttributes"
/>
<field-translated
<translated
v-if="field.isTranslated && !isAdvancedQuery"
:field-attributes="fieldAttributes"
:record-uuid="field.recordUuid"
/>
<calculator
v-if="!isAdvancedQuery && isNumeric"
:field-attributes="fieldAttributes"
:field-value="field.value"
/>
</template>
<component
:is="componentRender"
@ -65,10 +70,11 @@
</template>
<script>
import FieldContextInfo from '@/components/ADempiere/Field/fieldPopovers/fieldContextInfo'
import FieldDocumentStatus from '@/components/ADempiere/Field/fieldPopovers/fieldDocumentStatus'
import FieldOperatorComparison from '@/components/ADempiere/Field/fieldPopovers/fieldOperatorComparison'
import FieldTranslated from '@/components/ADempiere/Field/fieldPopovers/fieldTranslated'
import contextInfo from '@/components/ADempiere/Field/popover/contextInfo'
import documentStatus from '@/components/ADempiere/Field/popover/documentStatus'
import operatorComparison from '@/components/ADempiere/Field/popover/operatorComparison'
import translated from '@/components/ADempiere/Field/popover/translated'
import calculator from '@/components/ADempiere/Field/popover/calculator'
import { FIELD_ONLY } from '@/components/ADempiere/Field/references'
import { DEFAULT_SIZE } from '@/components/ADempiere/Field/fieldSize'
import { fieldIsDisplayed } from '@/utils/ADempiere/dictionaryUtils'
@ -81,10 +87,11 @@ import { showMessage } from '@/utils/ADempiere/notification'
export default {
name: 'FieldDefinition',
components: {
FieldContextInfo,
FieldDocumentStatus,
FieldOperatorComparison,
FieldTranslated
contextInfo,
documentStatus,
operatorComparison,
translated,
calculator
},
props: {
parentUuid: {
@ -263,6 +270,9 @@ export default {
return (this.field.contextInfo && this.field.contextInfo.isActive) || this.field.reference.windowsList.length
}
return false
},
isNumeric() {
return this.field.componentPath === 'FieldNumber'
}
},
watch: {

View File

@ -0,0 +1,311 @@
<template>
<el-dropdown trigger="click">
<el-button type="text">
<i class="el-icon-s-operation el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown" class="dropdown-calc">
<el-input
v-model="calcValue"
v-shortkey="['enter']"
class="calc-input"
@keydown.native="calculateValue"
@shortkey.native="changeValue"
>
<template slot="append">{{ valueToDisplay }}</template>
</el-input>
<el-table
ref="calculator"
:data="tableData"
style="width: 100%"
border
:show-header="false"
:span-method="spanMethod"
class="calc-table"
@cell-click="sendValue"
>
<el-table-column
align="center"
prop="row1"
height="50"
width="50"
>
<template slot-scope="{ row, column }">
<el-button type="text" :disabled="isDisabled(row, column)">{{ row.row1.value }}</el-button>
</template>
</el-table-column>
<el-table-column
align="center"
prop="row2"
height="50"
width="50"
>
<template slot-scope="{ row, column }">
<el-button type="text" :disabled="isDisabled(row, column)">{{ row.row2.value }}</el-button>
</template>
</el-table-column>
<el-table-column
align="center"
prop="row3"
height="50"
width="50"
>
<template slot-scope="{ row, column }">
<el-button type="text" :disabled="isDisabled(row, column)">{{ row.row3.value }}</el-button>
</template>
</el-table-column>
<el-table-column
align="center"
prop="row4"
height="50"
width="50"
>
<template slot-scope="{ row, column }">
<el-button type="text" :disabled="isDisabled(row, column)">{{ row.row4.value }}</el-button>
</template>
</el-table-column>
<el-table-column
align="center"
prop="row5"
height="50"
width="50"
>
<template slot-scope="{ row, column }">
<el-button type="text" :disabled="isDisabled(row, column)">{{ row.row5.value }}</el-button>
</template>
</el-table-column>
</el-table>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
name: 'FieldCalc',
props: {
fieldAttributes: {
type: Object,
required: true
},
fieldValue: {
type: Number,
default: undefined
}
},
data() {
return {
calcValue: this.fieldValue,
valueToDisplay: '',
tableData: [{
row1: {
type: 'operator',
value: '%'
},
row2: {
type: 'operator',
value: '/'
},
row3: {
type: 'operator',
value: '*'
},
row4: {
type: 'operator',
value: '-'
},
row5: {
type: 'clear',
value: 'C'
}
}, {
row1: {
type: 'value',
value: 7
},
row2: {
type: 'value',
value: 8
},
row3: {
type: 'value',
value: 9
},
row4: {
type: 'operator',
value: '+'
},
row5: {
type: 'clear',
value: 'AC'
}
}, {
row1: {
type: 'value',
value: 4
},
row2: {
type: 'value',
value: 5
},
row3: {
type: 'value',
value: 7
},
row4: {
type: 'operator',
value: '('
},
row5: {
type: undefined,
value: undefined
}
}, {
row1: {
type: 'value',
value: 1
},
row2: {
type: 'value',
value: 2
},
row3: {
type: 'value',
value: 3
},
row4: {
type: 'result',
value: '='
},
row5: {
type: 'operator',
value: ')'
}
}, {
row1: {
type: 'value',
value: 0
},
row2: {
type: 'operator',
value: '.'
},
row3: {
type: 'operator',
value: '+/-'
},
row4: {
type: undefined,
value: undefined
},
row5: {
type: undefined,
value: undefined
}
}]
}
},
watch: {
fieldValue(value) {
this.calcValue = value
}
},
methods: {
sendValue(row, column) {
const isAcceptedType = ['result', 'clear'].includes(row[column.property].type)
if (!isAcceptedType && !this.isDisabled(row, column)) {
this.calcValue += row[column.property].value
}
if (row[column.property].type === 'clear') {
if (row[column.property].value === 'C') {
this.calcValue = this.calcValue.slice(0, -1)
} else if (row[column.property].value === 'AC') {
this.calcValue = ''
}
}
if (row[column.property].value === '=') {
this.changeValue()
}
},
changeValue() {
const result = Number(this.valueToDisplay)
this.$store.dispatch('notifyFieldChange', {
isAdvancedQuery: this.fieldAttributes.isAdvancedQuery,
panelType: this.fieldAttributes.panelType,
parentUuid: this.fieldAttributes.parentUuid,
containerUuid: this.fieldAttributes.containerUuid,
columnName: this.fieldAttributes.columnName,
newValue: result,
field: this.fieldAttributes,
isChangedOldValue: true
})
.finally(() => {
this.clearVariables()
})
},
spanMethod({ row, column, rowIndex, columnIndex }) {
if (rowIndex === 1) {
if (row[column.property].value === '+') {
return {
rowspan: 2,
colspan: 1
}
}
} else if (rowIndex === 2) {
if (this.isEmptyValue(row[column.property].value)) {
return {
rowspan: 0,
colspan: 0
}
}
} else if (rowIndex === 3) {
if (row[column.property].value === '=') {
return {
rowspan: 2,
colspan: 1
}
}
} else if (rowIndex === 4) {
if (row[column.property].value === 0) {
return {
rowspan: 1,
colspan: 2
}
} else if (this.isEmptyValue(row[column.property].value)) {
return {
rowspan: 0,
colspan: 0
}
}
}
},
isDisabled(row, column) {
const isInteger = ['Integer', 'ID'].includes(this.fieldAttributes.referenceType)
const value = row[column.property].value
if (isInteger && value === ',') {
return true
}
return false
},
calculateValue(event) {
const result = this.calculationValue(this.fieldValue, event)
if (!this.isEmptyValue(result)) {
this.valueToDisplay = result
} else {
this.valueToDisplay = '...'
}
}
}
}
</script>
<style>
.el-table--enable-row-hover .el-table__body tr:hover > td {
background-color: #ffffff !important;
}
.calc-table .el-table__body-wrapper > table {
border-spacing: 5px;
}
.calc-table .el-table__body tr > td {
box-shadow: 0px 0px 3px 0px rgba(0,0,0,0.5);
border-radius: 5px;
cursor: pointer;
}
</style>

View File

@ -290,11 +290,13 @@ const data = {
value: valueGetDisplayColumn
})
.then(responseLookup => {
dispatch('addDisplayColumn', {
containerUuid,
columnName: itemField.columnName,
displayColumn: responseLookup.label
})
if (responseLookup) {
dispatch('addDisplayColumn', {
containerUuid,
columnName: itemField.columnName,
displayColumn: responseLookup.label
})
}
})
})
}
@ -626,12 +628,14 @@ const data = {
value: valueToReturn.key
})
.then(responseLookup => {
valueToReturn.label = responseLookup.label
dispatch('addDisplayColumn', {
containerUuid: field.containerUuid,
columnName: field.columnName,
displayColumn: responseLookup.label
})
if (responseLookup) {
valueToReturn.label = responseLookup.label
dispatch('addDisplayColumn', {
containerUuid: field.containerUuid,
columnName: field.columnName,
displayColumn: responseLookup.label
})
}
})
}
resolve(valueToReturn)

View File

@ -407,22 +407,24 @@ const panel = {
value: newValues[actionField.columnName]
})
.then(response => {
dispatch('notifyFieldChange', {
isSendToServer,
isSendCallout,
isAdvancedQuery,
panelType,
parentUuid,
containerUuid,
columnName: actionField.columnName,
displayColumn: response.label,
newValue: newValues[actionField.columnName],
valueTo: newValues[`${actionField.columnName}_To`],
fieldList,
field: actionField,
withOutColumnNames,
isChangedOldValue: true // defines if set oldValue with newValue instead of current value
})
if (!isEmptyValue(response)) {
dispatch('notifyFieldChange', {
isSendToServer,
isSendCallout,
isAdvancedQuery,
panelType,
parentUuid,
containerUuid,
columnName: actionField.columnName,
displayColumn: response.label,
newValue: newValues[actionField.columnName],
valueTo: newValues[`${actionField.columnName}_To`],
fieldList,
field: actionField,
withOutColumnNames,
isChangedOldValue: true // defines if set oldValue with newValue instead of current value
})
}
})
} else {
newValues[`DisplayColumn_${actionField.columnName}`] = lookup.label

View File

@ -2,5 +2,7 @@
export {
isEmptyValue,
zeroPad,
tagStatus
tagStatus,
calculationValue,
clearVariables
} from '@/utils/ADempiere/valueUtils.js'

View File

@ -415,3 +415,30 @@ export function tagStatus(tag) {
}
return type
}
let partialValue = ''
export function calculationValue(value, event) {
const VALIDATE_EXPRESSION = /[^\d\/.()%\*\+\-]/gim
if (!this.isEmptyValue(event) && !VALIDATE_EXPRESSION.test(event.key)) {
partialValue += event.key
const operation = String(value) + partialValue
if (!isEmptyValue(operation)) {
try {
// eslint-disable-next-line no-eval
return eval(operation) + ''
} catch (error) {
return null
}
}
} else {
if (value.key === 'Backspace') {
partialValue = partialValue.slice(0, -1)
} else {
return null
}
}
}
export function clearVariables() {
partialValue = ''
}