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

Add product information form (#551)

* Add Form The PorductInfo

* remove console.log
This commit is contained in:
Elsio Sanchez 2020-12-01 19:39:39 -04:00 committed by GitHub
parent 1e40283c4e
commit 210443b395
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 559 additions and 4 deletions

View File

@ -0,0 +1,12 @@
export default [
// Product Code
{
elementColumnName: 'ProductValue',
columnName: 'ProductValue',
isFromDictionary: true,
overwriteDefinition: {
size: 24,
sequence: 10
}
}
]

View File

@ -0,0 +1,173 @@
<template>
<div>
<product-info-list />
</div>
</template>
<script>
/**
* This component is made to be the prototype of the Product Info search field
*/
import ProductInfoList from './productList'
import fieldMixin from '@/components/ADempiere/Field/mixin/mixinField.js'
import {
formatPrice,
formatQuantity
} from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'ProductInfo',
components: {
ProductInfoList
},
mixins: [
fieldMixin
],
data() {
return {
timeOut: null
}
},
computed: {
isShowProductsPriceList: {
get() {
return this.$store.state['pointOfSales/listProductPrice'].productPrice.isShowPopoverField
},
set(isShowed) {
if (!this.isEmptyValue(this.$route.query.pos)) {
this.$store.commit('showListProductPrice', {
attribute: 'isShowPopoverField',
isShowed
})
}
}
},
listWithPrice() {
const { productPricesList } = this.$store.getters.getProductPrice
if (!this.isEmptyValue(productPricesList)) {
return productPricesList
}
return []
},
keyShortcuts() {
return {
refreshList: ['f5'],
refreshList2: ['shift', 'f5']
}
}
},
methods: {
formatPrice,
formatQuantity,
shortcutKeyMethod(event) {
console.log(event)
switch (event.srcKey) {
case 'refreshList':
case 'refreshList2':
this.$store.dispatch('listProductPriceFromServerProductInfo', {})
break
}
},
localSearch(stringToMatch, callBack) {
if (this.isEmptyValue(stringToMatch)) {
// not show list
callBack([])
return
}
console.log(stringToMatch, callBack)
let results = this.listWithPrice
if (stringToMatch) {
const parsedValue = stringToMatch.toLowerCase().trim()
results = results.filter(rowProduct => {
const productAttributes = rowProduct.product
for (const columnProductPrice in productAttributes) {
const valueToCompare = String(productAttributes[columnProductPrice]).toLowerCase()
if (valueToCompare.includes(parsedValue)) {
return true
}
}
return false
})
// Remote search
if (this.isEmptyValue(results) && String(stringToMatch.length > 3)) {
clearTimeout(this.timeOut)
const epa = this.$store.getters.getSearchProduct
console.log({ epa })
this.timeOut = setTimeout(() => {
this.$store.dispatch('listProductPriceFromServerProductInfo', {
containerUuid: 'Products-Price-List-ProductInfo',
pageNumber: 1,
searchValue: stringToMatch
})
.then(() => {
const recordsList = this.listWithPrice
if (this.isEmptyValue(recordsList)) {
this.$message({
message: 'Sin resultados coincidentes con la busqueda',
type: 'info',
showClose: true
})
}
callBack(recordsList)
})
}, 2000)
return
}
}
// call callback function to return suggestions
callBack(results)
},
handleSelect(elementSelected) {
const valueProduct = elementSelected.product.value
this.$store.dispatch('notifyActionKeyPerformed', {
containerUuid: 'POS',
columnName: 'ProductValue',
// TODO: Verify with 'value' or 'searchValue' attribute
value: valueProduct
})
}
}
}
</script>
<style lang="scss" scope>
.custom-field-prodcut-info {
li {
line-height: normal;
padding: 15px;
.header {
text-overflow: ellipsis;
overflow: hidden;
}
.upc {
color: #7e7e7e;
padding-top: 10px;
float: left;
}
.description {
padding-top: 10px;
float: left;
}
.price {
color: #7e7e7e;
padding-top: 10px;
float: right;
padding-right: 10px;
}
.quantityAvailable {
float: right;
padding-top: 10px;
}
}
}
</style>

View File

@ -0,0 +1,269 @@
<template>
<el-main
v-shortkey="shortsKey"
>
<el-form
v-shortkey="shortsKey"
label-position="top"
label-width="10px"
@shortkey.native="keyAction"
@submit.native.prevent="notSubmitForm"
>
<field-definition
v-for="(field) in fieldsList"
:key="field.columnName"
:metadata-field="field"
/>
</el-form>
<el-table
ref="singleTable"
v-loading="!productPrice.isLoaded"
:data="listWithPrice"
border
fit
height="550"
highlight-current-row
@row-click="findlistProductWithRow"
@current-change="handleCurrentChange"
>
<el-table-column
prop="product.value"
label="Codigo"
/>
<el-table-column
label="Producto"
>
<template slot-scope="scope">
<el-popover trigger="click" placement="right" width="300">
<b><i> {{ scope.row.product.name }} </i> </b>
<el-divider />
<p><b style="float: left"> Codigo :</b><spam style="float: right">{{ scope.row.product.value }}</spam></p><br>
<p><b style="float: left">Precio :</b><spam style="float: right"> {{ formatPrice(scope.row.priceStandard, scope.row.currency.iSOCode) }} </spam></p><br>
<p><b style="float: left">Tax :</b><spam style="float: right"> {{ formatPrice(getTaxAmount(scope.row.priceStandard, scope.row.taxRate.rate), scope.row.currency.iSOCode) }} </spam></p><br>
<p><b style="float: left">Gran Total :</b><spam style="float: right"> {{ formatPrice(getTaxAmount(scope.row.priceStandard, scope.row.taxRate.rate) + scope.row.priceStandard, scope.row.currency.iSOCode) }} </spam></p><br>
<p><b style="float: left">UPC :</b><spam style="float: right"> {{ scope.row.product.upc }} </spam></p>
<div slot="reference" class="name-wrapper">
{{ scope.row.product.name }}
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column
label="Tax"
align="right"
width="150"
>
<template slot-scope="scope">
{{ formatPrice(getTaxAmount(scope.row.priceStandard, scope.row.taxRate.rate), scope.row.currency.iSOCode) }}
</template>
</el-table-column>
<el-table-column
label="Precio"
align="right"
width="200"
>
<template slot-scope="scope">
{{ formatPrice(scope.row.priceStandard, scope.row.currency.iSOCode) }}
</template>
</el-table-column>
<el-table-column
label="Gran Total"
align="right"
width="300"
>
<template slot-scope="scope">
{{ formatPrice(getTaxAmount(scope.row.priceStandard, scope.row.taxRate.rate) + scope.row.priceStandard, scope.row.currency.iSOCode) }}
</template>
</el-table-column>
</el-table>
<custom-pagination
:total="productPrice.recordCount"
:current-page="productPrice.pageNumber"
:handle-change-page="handleChangePage"
/>
</el-main>
</template>
<script>
import formMixin from '@/components/ADempiere/Form/formMixin.js'
import CustomPagination from '@/components/ADempiere/Pagination'
import fieldsListProductPrice from './fieldsList.js'
import { formatPrice } from '@/utils/ADempiere/valueFormat.js'
export default {
name: 'ProductList',
components: {
CustomPagination
},
mixins: [
formMixin
],
props: {
metadata: {
type: Object,
default: () => {
return {
uuid: 'Products-Price-List-ProductInfo',
containerUuid: 'Products-Price-List-ProductInfo'
}
}
},
isSelectable: {
type: Boolean,
default: true
},
popoverName: {
type: String,
default: 'isShowPopoverField'
}
},
data() {
return {
defaultMaxPagination: 50,
resource: {},
fieldsList: fieldsListProductPrice,
isCustomForm: true,
timeOut: null
}
},
computed: {
defaultImage() {
return require('@/image/ADempiere/pos/no-image.jpg')
},
isShowProductsPriceList() {
return this.$store.state['pointOfSales/listProductPrice'].productPrice[this.attribute]
},
currentPoint() {
return this.$store.getters.getCurrentPOS
},
productPrice() {
return this.$store.getters.getProductPrice
},
listWithPrice() {
const { productPricesList } = this.productPrice
if (!this.isEmptyValue(productPricesList)) {
return productPricesList
}
return []
},
shortsKey() {
return {
closeProductList: ['esc'],
refreshList: ['f5']
}
},
isReadyFromGetData() {
const { isLoaded, isReload } = this.productPrice
return (!isLoaded || isReload) // && this.isShowProductsPriceList
}
},
watch: {
isReadyFromGetData(isToLoad) {
if (isToLoad) {
this.loadProductsPricesList()
}
}
},
created() {
this.$store.dispatch('listPointOfSalesFromServer')
this.unsubscribe = this.subscribeChanges()
if (this.isReadyFromGetData) {
this.loadProductsPricesList()
}
},
beforeDestroy() {
this.unsubscribe()
},
methods: {
formatPrice,
srcImage(keyValue) {
if (this.isEmptyValue(keyValue)) {
return this.defaultImage
}
// const image = this.valuesImage.find(item => item.identifier === fileName).value
const image = this.resource[keyValue]
if (this.isEmptyValue(image)) {
return this.defaultImage
}
return image
},
setCurrent(row) {
this.$refs.singleTable.setCurrentRow(row)
},
handleCurrentChange(val) {
this.currentRow = val
this.setCurrent(this.currentRow)
},
keyAction(event) {
switch (event.srcKey) {
case 'refreshList':
/**
* TODO: When refreshing you are making 2 list requests, you can be the
* observer that activates the second request
*/
this.loadProductsPricesList()
break
case 'closeProductList':
this.$store.commit('showListProductPrice', {
attribute: this.popoverName,
isShowed: false
})
break
}
},
loadProductsPricesList() {
this.$store.dispatch('listProductPriceFromServerProductInfo', {})
},
/**
* @param {number} newPage
*/
handleChangePage(newPage) {
this.$store.dispatch('setProductPicePageNumber', newPage)
},
findlistProductWithRow(row) {
if (!this.isSelectable) {
return
}
// TODO: Change this dispatch for set values with local methods, to delete subscripton
this.$store.dispatch('notifyActionKeyPerformed', {
containerUuid: 'POS',
columnName: 'ProductValue',
// TODO: Verify with 'value' or 'searchValue' attribute
value: row.product.name
})
// close popover of list product price
this.$store.commit('showListProductPrice', {
attribute: this.popoverName,
isShowed: false
})
},
getTaxAmount(basePrice, taxRate) {
if (this.isEmptyValue(basePrice) || this.isEmptyValue(taxRate)) {
return 0
}
return (basePrice * taxRate) / 100
},
subscribeChanges() {
return this.$store.subscribe((mutation, state) => {
// if (!this.isEmptyValue(this.listWithPrice)) {
// this.setCurrent(this.listWithPrice[0])
// }
if (mutation.type === 'updateValueOfField' &&
!mutation.payload.columnName.includes('DisplayColumn') &&
mutation.payload.containerUuid === this.metadata.containerUuid) {
clearTimeout(this.timeOut)
this.timeOut = setTimeout(() => {
this.$store.dispatch('updateSearch', mutation.payload.value)
this.$store.commit('setIsReloadProductPrice')
}, 1000)
}
})
}
}
}
</script>

View File

@ -182,6 +182,7 @@ export default {
this.timeOut = setTimeout(() => {
this.$store.dispatch('listProductPriceFromServer', {
containerUuid: 'Products-Price-List',
pageNumber: 1,
searchValue: stringToMatch
})

View File

@ -34,6 +34,9 @@ export default {
case 'BarcodeReader':
form = import('@/components/ADempiere/Form/BarcodeReader')
break
case 'ProductInfo':
form = import('@/components/ADempiere/Form/ProductInfo')
break
case 'VPOS':
form = import('@/components/ADempiere/Form/VPOS')
break

View File

@ -98,6 +98,22 @@ const staticRoutes = [
}
}
]
},
{
path: '/ProductInfo',
component: Layout,
hidden: false,
children: [
{
path: '/ProductInfo',
component: () => import('@/views/ADempiere/Form'),
name: 'ProductInfo',
meta: {
title: 'ProductInfo',
isIndex: true
}
}
]
}
]

View File

@ -49,7 +49,7 @@ export default {
})
})
.catch(error => {
console.warn(`Error getting epale error en guardar: ${error.message}. Code: ${error.code}.`)
console.warn(`Error getting ProductInfo error en guardar: ${error.message}. Code: ${error.code}.`)
})
},
listChatEntries({ commit }, {

View File

@ -18,7 +18,8 @@ const listProductPrice = {
...withoutResponse,
isShowPopoverField: false, // with field
isShowPopoverMenu: false // with menu
}
},
searchProduct: ''
},
mutations: {
setListProductPrice(state, productsPrices) {
@ -36,6 +37,9 @@ const listProductPrice = {
setIsReloadProductPrice(state) {
Vue.set(state.productPrice, 'isReload', true)
Vue.set(state.productPrice, 'isLoaded', false)
},
updtaeSearchProduct(state, searchProduct) {
state.searchProduct = searchProduct
}
},
actions: {
@ -61,7 +65,6 @@ const listProductPrice = {
console.warn(message)
return
}
commit('setIsReloadProductPrice')
let pageToken, token
if (isEmptyValue(pageNumber)) {
@ -87,7 +90,6 @@ const listProductPrice = {
columnName: 'ProductValue'
})
}
return new Promise(resolve => {
requestListProductPrice({
searchValue,
@ -120,6 +122,82 @@ const listProductPrice = {
})
})
})
},
listProductPriceFromServerProductInfo({ state, commit, rootGetters }, {
containerUuid = 'Products-Price-List-ProductInfo',
pageNumber, // 1
searchValue
}) {
const posUuid = rootGetters.getPointOfSalesUuid
if (isEmptyValue(posUuid)) {
const message = 'Sin punto de venta seleccionado'
showMessage({
type: 'info',
message
})
console.warn(message)
return
}
commit('setIsReloadProductPrice')
let pageToken, token
if (isEmptyValue(pageNumber)) {
pageNumber = state.productPrice.pageNumber
if (isEmptyValue(pageNumber)) {
pageNumber = 1
}
token = state.productPrice.token
if (!isEmptyValue(token)) {
pageToken = token + '-' + pageNumber
}
}
const { priceList, templateBusinessPartner } = rootGetters.getCurrentPOS
const { uuid: businessPartnerUuid } = templateBusinessPartner
const { uuid: priceListUuid } = priceList
const { uuid: warehouseUuid } = rootGetters['user/getWarehouse']
if (isEmptyValue(searchValue)) {
searchValue = rootGetters.getValueOfField({
containerUuid,
columnName: 'ProductValue'
})
}
return new Promise(resolve => {
requestListProductPrice({
searchValue,
priceListUuid,
businessPartnerUuid,
warehouseUuid,
pageToken
}).then(responseProductPrice => {
if (isEmptyValue(token) || isEmptyValue(pageToken)) {
token = extractPagingToken(responseProductPrice.nextPageToken)
}
commit('setListProductPrice', {
...responseProductPrice,
isLoaded: true,
isReload: false,
businessPartnerUuid,
warehouseUuid,
token,
pageNumber
})
resolve(responseProductPrice)
}).catch(error => {
console.warn(`getKeyLayoutFromServer: ${error.message}. Code: ${error.code}.`)
showMessage({
type: 'error',
message: error.message,
showClose: true
})
})
})
},
updateSearch({ commit }, newValue) {
commit('updtaeSearchProduct', newValue)
}
},
getters: {
@ -131,6 +209,9 @@ const listProductPrice = {
}
}
return state.productPrice
},
getSearchProduct: (state) => {
return state.searchProduct
}
}
}