Add basic components for Product CRUD
more specifically at this point, for product lookup via scanner
This commit is contained in:
parent
6db418ec19
commit
4fa08c68ec
|
@ -7,6 +7,8 @@ import ByjoveLogin from './login'
|
||||||
import ByjoveAutocomplete from './autocomplete'
|
import ByjoveAutocomplete from './autocomplete'
|
||||||
import ByjoveModelIndex from './model-index'
|
import ByjoveModelIndex from './model-index'
|
||||||
import ByjoveModelCrud from './model-crud'
|
import ByjoveModelCrud from './model-crud'
|
||||||
|
import ByjoveScannerInput from './scanner-input'
|
||||||
|
import {ByjoveProducts, ByjoveProduct} from './products'
|
||||||
import ByjoveCustomerField from './customers'
|
import ByjoveCustomerField from './customers'
|
||||||
import ByjoveInventory from './inventory'
|
import ByjoveInventory from './inventory'
|
||||||
import ByjoveReceiving from './receiving'
|
import ByjoveReceiving from './receiving'
|
||||||
|
@ -21,6 +23,9 @@ export {
|
||||||
ByjoveAutocomplete,
|
ByjoveAutocomplete,
|
||||||
ByjoveModelIndex,
|
ByjoveModelIndex,
|
||||||
ByjoveModelCrud,
|
ByjoveModelCrud,
|
||||||
|
ByjoveScannerInput,
|
||||||
|
ByjoveProducts,
|
||||||
|
ByjoveProduct,
|
||||||
ByjoveCustomerField,
|
ByjoveCustomerField,
|
||||||
ByjoveInventory,
|
ByjoveInventory,
|
||||||
ByjoveReceiving,
|
ByjoveReceiving,
|
||||||
|
|
|
@ -62,6 +62,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
wantInitialResults: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
allowCreate: {
|
allowCreate: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
|
@ -83,7 +87,9 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchData()
|
if (this.wantInitialResults) {
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'apiIndexFilters' (to, from) {
|
'apiIndexFilters' (to, from) {
|
||||||
|
|
90
src/components/products/ByjoveProduct.vue
Normal file
90
src/components/products/ByjoveProduct.vue
Normal 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>
|
55
src/components/products/ByjoveProducts.vue
Normal file
55
src/components/products/ByjoveProducts.vue
Normal 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>
|
7
src/components/products/index.js
Normal file
7
src/components/products/index.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import ByjoveProducts from './ByjoveProducts'
|
||||||
|
import ByjoveProduct from './ByjoveProduct'
|
||||||
|
|
||||||
|
export {
|
||||||
|
ByjoveProducts,
|
||||||
|
ByjoveProduct,
|
||||||
|
}
|
56
src/components/scanner-input/ByjoveScannerInput.vue
Normal file
56
src/components/scanner-input/ByjoveScannerInput.vue
Normal 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>
|
28
src/components/scanner-input/index.js
Normal file
28
src/components/scanner-input/index.js
Normal 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
|
Loading…
Reference in a new issue