Add basic components for Product CRUD

more specifically at this point, for product lookup via scanner
This commit is contained in:
Lance Edgar 2023-01-04 20:24:01 -06:00
parent 6db418ec19
commit 4fa08c68ec
7 changed files with 248 additions and 1 deletions

View file

@ -7,6 +7,8 @@ import ByjoveLogin from './login'
import ByjoveAutocomplete from './autocomplete'
import ByjoveModelIndex from './model-index'
import ByjoveModelCrud from './model-crud'
import ByjoveScannerInput from './scanner-input'
import {ByjoveProducts, ByjoveProduct} from './products'
import ByjoveCustomerField from './customers'
import ByjoveInventory from './inventory'
import ByjoveReceiving from './receiving'
@ -21,6 +23,9 @@ export {
ByjoveAutocomplete,
ByjoveModelIndex,
ByjoveModelCrud,
ByjoveScannerInput,
ByjoveProducts,
ByjoveProduct,
ByjoveCustomerField,
ByjoveInventory,
ByjoveReceiving,

View file

@ -62,6 +62,10 @@ export default {
type: Boolean,
default: false,
},
wantInitialResults: {
type: Boolean,
default: true,
},
allowCreate: {
type: Boolean,
default: true,
@ -83,7 +87,9 @@ export default {
}
},
mounted() {
this.fetchData()
if (this.wantInitialResults) {
this.fetchData()
}
},
watch: {
'apiIndexFilters' (to, from) {

View file

@ -0,0 +1,90 @@
<template>
<byjove-model-crud model-name="Product"
:allow-edit="allowEdit"
:mode="mode"
@refresh="record => { product = record }">
<div style="display: flex; justify-content: space-between; margin-bottom: 0.5rem;">
<b-field label="Item ID">
<b-input v-if="mode == 'creating' || mode == 'editing'"
v-model="product.item_id">
</b-input>
<span v-if="mode == 'viewing' || mode == 'deleting'">
{{ product.item_id }}
</span>
</b-field>
<img :src="product.image_url" />
</div>
<b-collapse class="card"
animation="slide"
:open="false"
aria-id="contentIdForVendors">
<template #trigger="props">
<div class="card-header"
role="button"
aria-controls="contentIdForVendors"
:aria-expanded="props.open">
<p class="card-header-title">
Vendors
</p>
<a class="card-header-icon">
<b-icon pack="fas"
:icon="props.open ? 'angle-down' : 'angle-up'">
</b-icon>
</a>
</div>
</template>
<div class="card-content">
<div class="content">
<b-field label="Preferred Vendor">
{{ product.vendor_name }} @ {{ product.default_unit_cost_display }}
</b-field>
<b-table :data="product.costs">
<b-table-column label="Vendor"
field="vendor_name"
v-slot="props">
{{ props.row.vendor_name }}
</b-table-column>
<b-table-column label="Unit Cost"
field="unit_cost"
v-slot="props">
{{ props.row.unit_cost }}
</b-table-column>
</b-table>
</div>
</div>
</b-collapse>
</byjove-model-crud>
</template>
<script>
import ByjoveModelCrud from '../model-crud'
export default {
name: 'Product',
props: {
mode: String,
allowEdit: {
type: Boolean,
default: false,
},
},
components: {
ByjoveModelCrud,
},
data: function() {
return {
product: {},
}
},
}
</script>

View file

@ -0,0 +1,55 @@
<template>
<byjove-model-index model-name="Product"
:want-initial-results="wantInitialResults"
:allow-create="allowCreate">
<byjove-scanner-input @submit="scannerSubmit">
</byjove-scanner-input>
</byjove-model-index>
</template>
<script>
import ByjoveModelIndex from '../model-index'
import ByjoveScannerInput from '../scanner-input'
export default {
name: 'ByjoveProducts',
components: {
ByjoveModelIndex,
ByjoveScannerInput,
},
props: {
wantInitialResults: {
type: Boolean,
default: false,
},
allowCreate: {
type: Boolean,
default: false,
},
},
methods: {
scannerSubmit(entry) {
let url = '/api/products/quick-lookup'
let params = {entry: entry}
this.$http.get(url, {params: params}).then(response => {
if (response.data.error) {
this.$buefy.toast.open({
message: response.data.error,
type: 'is-danger',
})
} else {
this.$router.push(`/products/${response.data.product.uuid}`)
}
}, response => {
this.$buefy.toast.open({
message: "Unknown error!",
type: 'is-danger',
})
})
},
},
}
</script>

View file

@ -0,0 +1,7 @@
import ByjoveProducts from './ByjoveProducts'
import ByjoveProduct from './ByjoveProduct'
export {
ByjoveProducts,
ByjoveProduct,
}

View file

@ -0,0 +1,56 @@
<template>
<div class="scanner-input">
<b-input v-model="quickEntry"
placeholder="Scan/Enter Code"
icon="search"
@keypress.native="quickKey">
</b-input>
</div>
</template>
<script>
export default {
name: 'ByjoveScannerInput',
data() {
return {
quickEntry: '',
}
},
mounted() {
window.addEventListener('keypress', this.globalKey)
},
beforeDestroy() {
window.removeEventListener('keypress', this.globalKey)
},
methods: {
globalKey(event) {
if (event.target.tagName == 'BODY') {
// mimic keyboard wedge
if (event.charCode >= 48 && event.charCode <= 57) { // numeric (qwerty)
this.$nextTick(() => {
this.quickEntry += event.key
})
} else if (event.keyCode == 13) { // enter
this.submitQuickEntry()
}
}
},
quickKey(event) {
if (event.keyCode == 13) { // enter
this.submitQuickEntry()
}
},
submitQuickEntry() {
if (this.quickEntry) {
this.$emit('submit', this.quickEntry)
}
},
},
}
</script>

View file

@ -0,0 +1,28 @@
// Import vue component
import ByjoveScannerInput from './ByjoveScannerInput.vue'
// Declare install function executed by Vue.use()
export function install(Vue) {
if (install.installed) return;
install.installed = true;
Vue.component('ByjoveScannerInput', ByjoveScannerInput);
}
// Create module definition for Vue.use()
const plugin = {
install,
};
// Auto-install when vue is found (eg. in browser via <script> tag)
let GlobalVue = null;
if (typeof window !== 'undefined') {
GlobalVue = window.Vue;
} else if (typeof global !== 'undefined') {
GlobalVue = global.Vue;
}
if (GlobalVue) {
GlobalVue.use(plugin);
}
// To allow use as module (npm/webpack/etc.) export component
export default ByjoveScannerInput