[javascript] ppob.vue

Viewer

copydownloadembedprintName: ppob.vue
  1. <template>
  2.   <v-layout column fill-height justify-start>
  3.     <!-- TITLE ADD PRODUCT -->
  4.     <v-snackbar
  5.       :color="snackbar.color"
  6.       v-model="snackbar.value"
  7.       multi-line
  8.       top
  9.     >
  10.       {{snackbar.text}}
  11.       <v-btn dark flat @click.native="snackbar.value = false">Close</v-btn>
  12.     </v-snackbar>
  13.     <v-flex>
  14.       <v-layout row>
  15.         <v-flex>
  16.           <div class="title font-weight-bold">
  17.             Add Product {{ this.pageTitle }}
  18.           </div>
  19.         </v-flex>
  20.       </v-layout>
  21.     </v-flex>
  22.     <!-- END TITLE ADD PRODUCT  -->
  23.  
  24.     <!-- V-card -->
  25.     <v-flex xs12 md12 pt-3>
  26.       <v-layout row>
  27.         <v-flex>
  28.           <v-stepper v-model="stepper" class="elevation-2">
  29.             <v-stepper-header class="elevation-0">
  30.               <v-stepper-step :complete="stepper > 1" step="1">Product Information</v-stepper-step>
  31.               <v-divider></v-divider>
  32.               <v-stepper-step step="2">Unit Information</v-stepper-step>
  33.             </v-stepper-header>
  34.             <v-divider></v-divider>
  35.             <v-stepper-items>
  36.               <v-stepper-content step="1">
  37.                 <v-form v-model="valid" ref="pricelistForm">
  38.                   <v-flex class="py-2 mb-5" lg12 md12 sm12 xs12>
  39.                     <v-container grid-list-md fluid pa-0>
  40.                       <v-layout column>
  41.                         <v-flex>
  42.                           <v-layout row wrap>
  43.                             <v-flex xs12 sm3 class="subheading font-weight-bold">
  44.                               Product Information
  45.                             </v-flex>
  46.                             <v-flex xs12 sm4>
  47.                               <label for="business_unit" class="subheading">Product ID<span class="red--text">*</span></label>
  48.                               <v-text-field required v-model="idProduct" :rules="[idRules(idProduct)]" label="Product Id Klikdaily" solo class="solo-outline" :disabled="isEditMode"></v-text-field>
  49.                             </v-flex>
  50.                             <v-flex xs12 offset-sm3 sm6>
  51.                               <label id="product-name-provider-add-product" for="distribution_centre" class="subheading">Product Name</label>
  52.                               <v-text-field required v-model="productName" label="(ex. Pulsa Telkomsel 20.000)" solo class="solo-outline"></v-text-field>
  53.                             </v-flex>
  54.                             <v-flex xs12 offset-sm3 sm6>
  55.                               <label class="subheading">Description</label>
  56.                               <vueditor ref="descriptionEditor"></vueditor>
  57.                             </v-flex>
  58.                           </v-layout>
  59.                         </v-flex>
  60.                       </v-layout>
  61.                     </v-container>
  62.                   </v-flex>
  63.                 </v-form>
  64.                 <v-divider class="pt-3"></v-divider>
  65.                 <v-card-actions class="pb-4 pr-4">
  66.                   <v-spacer></v-spacer>
  67.                   <v-btn @click="cancel()" flat color="secondary">Cancel</v-btn>
  68.                   <v-btn :disabled="isNextButtonDisabled" @click="stepper = 2" depressed color="success">Next</v-btn>
  69.                 </v-card-actions>
  70.               </v-stepper-content>
  71.               <v-stepper-content step="2">
  72.                 <v-flex class="py-2 mb-5" lg12 md12 sm12 xs12>
  73.                   <v-container grid-list-md fluid pa-0>
  74.                     <v-layout column>
  75.                       <v-flex>
  76.                         <v-layout row wrap>
  77.                           <v-flex xs12 sm3 class="subheading font-weight-bold">
  78.                             Product Prices
  79.                           </v-flex>
  80.                           <v-flex xs12 sm9>
  81.                             <v-layout row wrap>
  82.                               <v-flex sm1></v-flex>
  83.                               <v-flex sm3>
  84.                                 <label for="business_unit" class="subheading font-weight-bold">{{ idProduct }} - {{ productName }}<span class="red--text">*</span></label>
  85.                               </v-flex>
  86.                             </v-layout>
  87.                             <v-layout row wrap v-for="(productPrice, index) in productPrices" :key="index">
  88.                               <v-flex sm1 v-if="index > 0" class="text-xs-right">
  89.                                 <v-icon 
  90.                                   color="red"
  91.                                   class="pt-4 mt-2"
  92.                                   v-on:click="removeNewProduct(index)"
  93.                                 >
  94.                                   remove_circle
  95.                                 </v-icon>
  96.                               </v-flex>
  97.                               <v-flex sm1 v-else>
  98.  
  99.                               </v-flex>
  100.                               <v-flex sm3>
  101.                                 <label for="business_unit" class="subheading">Select Vendor</label>
  102.                                 <v-autocomplete
  103.                                   solo
  104.                                   class="solo-outline"
  105.                                   :items="vendors"
  106.                                   return-object
  107.                                   v-model="productPrice.vendorSelected"
  108.                                   item-value="id"
  109.                                   @change="fetchProductIdVendor(productPrice.vendorSelected, index)"
  110.                                   :filter="autocompleteFilter"
  111.                                 >
  112.                                   <template v-slot:selection="data">
  113.                                     {{ data.item.name }}
  114.                                   </template>
  115.                                   <template v-slot:item="data">
  116.                                     {{ data.item.name }}
  117.                                   </template>
  118.                                 </v-autocomplete>
  119.                               </v-flex>
  120.                               <v-flex sm3>
  121.                                 <label for="business_unit" class="subheading">Product Id Vendor<span class="red--text">*</span></label>
  122.                                 <v-autocomplete
  123.                                   :loading="fetchVendorLoading"
  124.                                   solo
  125.                                   class="solo-outline"
  126.                                   :items="productPrice.vendorDetailProducts"
  127.                                   return-object
  128.                                   v-model="productPrice.vendorDetailProductSelected"
  129.                                   item-value="id"
  130.                                   :filter="autocompleteFilter"
  131.                                 >
  132.                                   <template v-slot:selection="data">
  133.                                     {{ data.item.name }}
  134.                                   </template>
  135.                                   <template v-slot:item="data">
  136.                                     {{ data.item.name }}
  137.                                   </template>
  138.                                 </v-autocomplete>
  139.                               </v-flex>
  140.                               <v-flex sm3>
  141.                                 <label for="business_unit" class="subheading">Buying Price</label>
  142.                                 <v-currency-field
  143.                                   solo
  144.                                   class="solo-outline"
  145.                                   :prefix="'Rp'"
  146.                                   type="number"
  147.                                   disabled
  148.                                   :decimal-length="0"
  149.                                   v-model.number="productPrice.vendorDetailProductSelected.purchase_price"
  150.                                   label="Price"
  151.                                 ></v-currency-field>
  152.                               </v-flex>
  153.                               <v-flex sm2>
  154.                                 <label for="business_unit" class="subheading">Price Status</label>
  155.                                 <v-switch
  156.                                   v-model="priceStatus"
  157.                                   :label="`${priceStatus ? 'Active' : 'Inactive'}`"
  158.                                   color="primary"
  159.                                 ></v-switch>
  160.                               </v-flex>
  161.                             </v-layout>
  162.                           </v-flex>
  163.                           <v-flex xs12 sm3></v-flex>
  164.                           <v-flex xs12 sm4 ml-5 pl-4>
  165.                             <v-btn color="warning" @click="addNewProduct()">Assign New Product</v-btn>
  166.                           </v-flex>
  167.                           <v-flex sm5></v-flex>
  168.                           <v-flex xs12 sm12>
  169.                             <v-divider></v-divider>
  170.                           </v-flex>
  171.                           <v-flex>
  172.                             <v-layout row wrap>
  173.                               <v-flex xs12 sm3 class="subheading font-weight-bold">
  174.                                 Selling Price
  175.                               </v-flex>
  176.                               <v-flex xs12 sm9>
  177.                                 <v-layout row wrap>
  178.                                   <v-flex sm1></v-flex>
  179.                                   <v-flex sm3>
  180.                                     <label for="business_unit" class="subheading">Selling Price</label>
  181.                                   </v-flex>
  182.                                 </v-layout>
  183.                                 <v-layout row wrap>
  184.                                   <v-flex sm1></v-flex>
  185.                                   <v-flex sm3>
  186.                                     <v-currency-field
  187.                                       solo
  188.                                       class="solo-outline"
  189.                                       :prefix="'Rp'"
  190.                                       type="number"
  191.                                       :decimal-length="0"
  192.                                       v-model.number="sellingPrice"
  193.                                       label="Price"
  194.                                     ></v-currency-field>
  195.                                   </v-flex>
  196.                                 </v-layout>
  197.                               </v-flex>
  198.                             </v-layout>
  199.                           </v-flex>
  200.                         </v-layout>
  201.                       </v-flex>
  202.                     </v-layout>
  203.                   </v-container>
  204.                 </v-flex>
  205.                 <v-divider class="mb-3"></v-divider>
  206.                 <v-card-actions class="pb-4 pr-4">
  207.                   <v-spacer></v-spacer>
  208.                   <v-btn @click="stepper = 1" flat color="secondary">Previous</v-btn>
  209.                   <v-btn id="confirm-modal-add-product-provider" @click="confirmModal()" depressed color="success">Confirm</v-btn>
  210.                 </v-card-actions>
  211.               </v-stepper-content>
  212.             </v-stepper-items>
  213.           </v-stepper>
  214.         </v-flex>
  215.       </v-layout>
  216.     </v-flex>
  217.     <!-- end v-card -->
  218.     <!-- Dialog confirmation -->
  219.     <v-dialog
  220.       v-model="dialogConfirmation" persistent max-width="600px" transition="dialog-transition"
  221.     >
  222.       <v-card>
  223.         <v-card-title>
  224.           <h1 class="title font-weight-bold">{{ mode === 'new' ? 'Add' : 'Edit' }} Product</h1>
  225.         </v-card-title>
  226.         <v-divider></v-divider>
  227.         <v-card-text>
  228.           Are you sure {{ mode === 'new' ? 'Created' : 'Edit' }} Product "{{ pageTitle }} {{ productName }}"?
  229.         </v-card-text>
  230.         <v-divider></v-divider>
  231.         <v-card-actions>
  232.           <v-spacer></v-spacer>
  233.           <v-btn color="dark" flat :disabled="loading === true" @click="closeDialogConfirmation()">Cancel</v-btn>
  234.           <v-btn color="primary" flat :loading="loading === true" @click="submit()">Yes</v-btn>
  235.         </v-card-actions>
  236.       </v-card>
  237.     </v-dialog>
  238.     <!-- LOADING -->
  239.       <v-dialog v-if="fullscreenLoading" v-model="fullscreenLoading" fullscreen full-width>
  240.         <v-container fluid fill-height style="background-color: rgba(255, 255, 255, 0.5);">
  241.           <v-layout justify-center align-center>
  242.             <v-progress-circular
  243.               indeterminate
  244.               color="primary">
  245.             </v-progress-circular>
  246.           </v-layout>
  247.         </v-container>
  248.       </v-dialog>
  249.       <!-- END LOADING -->
  250.   </v-layout>
  251. </template>
  252.  
  253. <script>
  254. import Vue from 'vue'
  255. import VeeValidate from 'vee-validate'
  256. import Vuex from 'vuex'
  257. // import 'vueditor/dist/style/vueditor.min.css'
  258. import Vueditor from 'vueditor'
  259.  
  260. let config = {
  261.   // for vueeditor
  262.   toolbar: [
  263.     'bold', 'italic', 'underline', '|',
  264.     'justifyLeft', 'justifyCenter', 'justifyRight', '|',
  265.     'insertOrderedList', 'insertUnorderedList', '|',
  266.     'undo', 'redo', '|',
  267.     'link'
  268.   ]
  269. }
  270.  
  271. Vue.use(VeeValidate, {fieldsBagName: 'vvFields'})
  272. Vue.use(Vuex)
  273. Vue.use(Vueditor, config)
  274.  
  275. export default {
  276.   $_veeValidate: {
  277.     validator: 'new'
  278.   },
  279.   components: {
  280.     ValidationProvider: VeeValidate.ValidationProvider
  281.   },
  282.   data: () => ({
  283.     vendorSelected: {},
  284.     productPrices: [
  285.       {
  286.         vendorDetailProducts: [],
  287.         vendorSelected: {},
  288.         vendorDetailProductSelected: {},
  289.         purchasePrice: 0,
  290.         priceStatus: true
  291.       }
  292.     ],
  293.     pageTitle: '',
  294.     loading: false,
  295.     mode: '',
  296.     priceStatus: true,
  297.     idProduct: '',
  298.     productName: '',
  299.     description: '',
  300.     stepper: 0,
  301.     valid: true,
  302.     sellingPrice: '',
  303.     fetchVendorLoading: false,
  304.     vendors: [],
  305.     vendorDetailProducts: [],
  306.     vendorDetailProductSelected: {},
  307.     dialogConfirmation: false,
  308.     editPPOBProductDetail: {},
  309.     fullscreenLoading: false,
  310.     snackbar: {
  311.       value: false,
  312.       text: '',
  313.       color: 'primary'
  314.     }
  315.   }),
  316.   created () {
  317.     this.defineMode()
  318.     this.definePageTitle()
  319.     this.fetchPPOBVendors()
  320.   },
  321.   watch: {
  322.     descriptionEditorContent (newValue) {
  323.       this.description = newValue
  324.     }
  325.   },
  326.   computed: {
  327.     descriptionEditorContent: {
  328.       get () {
  329.         if (`${this.mode}`.length > 0) {
  330.           return this.$refs.descriptionEditor.getContent()
  331.         }
  332.         return null
  333.       },
  334.       set (newContent) {
  335.         this.$refs.descriptionEditor.setContent(newContent)
  336.       }
  337.     },
  338.     isEditMode () {
  339.       return this.mode === 'edit'
  340.     },
  341.     isNextButtonDisabled () {
  342.       if (!this.idProduct) {
  343.         return true
  344.       } else return false
  345.     }
  346.   },
  347.   methods: {
  348.     defineMode () {
  349.       if (this.$route.params.id && this.$route.params.mode === 'edit') {
  350.         this.mode = 'edit'
  351.         this.fetchPPOBProductById()
  352.       } else {
  353.         this.mode = 'new'
  354.       }
  355.     },
  356.     closeDialogConfirmation () {
  357.       this.dialogConfirmation = false
  358.     },
  359.     paramsProductPricesForSubmit () {
  360.       let result = []
  361.       for (let i = 0; i < this.productPrices.length; i++) {
  362.         result.push({
  363.           product_id: this.productPrices[i].vendorDetailProductSelected.id,
  364.           name: this.productPrices[i].vendorDetailProductSelected.name,
  365.           price: this.productPrices[i].vendorDetailProductSelected.purchase_price,
  366.           status: this.productPrices[i].vendorDetailProductSelected.status
  367.         })
  368.       }
  369.       return result
  370.     },
  371.     async fetchPPOBProductById () {
  372.       this.fullscreenLoading = true
  373.       // console.log(this.$route.params.id_products)
  374.       await this.$store.dispatch('ppob/getPPOBProduct', this.$route.params.id_products).then(result => {
  375.         if (result.status === 200 || result.status === 201) {
  376.           this.editPPOBProductDetail = JSON.parse(JSON.stringify(result.data))
  377.           this.productName = this.editPPOBProductDetail.name
  378.           this.descriptionEditorContent = this.editPPOBProductDetail.description
  379.           this.description = this.editPPOBProductDetail.description
  380.           this.sellingPrice = this.editPPOBProductDetail.price
  381.           this.idProduct = this.editPPOBProductDetail.product_id
  382.           this.editPPOBProductDetail.vendors.forEach((vendor, index) => {
  383.             let tempVendorDetailProductSelected = {
  384.               purchase_price: vendor.price,
  385.               name: vendor.name,
  386.               id: vendor.product_id
  387.             }
  388.             if (index === 0) {
  389.               this.productPrices[index].vendorSelected = vendor
  390.               this.productPrices[index].vendorDetailProductSelected = tempVendorDetailProductSelected
  391.               this.productPrices[index].priceStatus = vendor.status
  392.             } else if (index > 0) {
  393.               this.productPrices.push({
  394.                 vendorSelected: vendor,
  395.                 vendorDetailProductSelected: tempVendorDetailProductSelected,
  396.                 priceStatus: true
  397.               })
  398.             }
  399.           })
  400.           this.fetchPPOBVendors()
  401.         } else {
  402.           this.snackbar = true
  403.           this.snackbarText = result.message
  404.           this.snackbarColor = 'error'
  405.           this.loading = false
  406.         }
  407.         this.fullscreenLoading = false
  408.       }).catch(error => {
  409.         this.fullscreenLoading = false
  410.         this.snackbar.value = true
  411.         this.snackbar.text = error.message
  412.         this.snackbar.color = 'error'
  413.         this.loading = false
  414.       })
  415.     },
  416.     async submit () {
  417.       this.loading = true
  418.       if (this.mode === 'new') {
  419.         let params = {
  420.           product_id: this.idProduct,
  421.           name: this.productName,
  422.           description: this.descriptionEditorContent,
  423.           price: this.sellingPrice,
  424.           type: 'mobile_credit',
  425.           provider: this.$route.params.id,
  426.           vendors: this.paramsProductPricesForSubmit()
  427.         }
  428.         // console.log('params', params)
  429.         await this.$store.dispatch('ppob/addPPOBProducts', params).then(result => {
  430.           if (result.status === 200 || result.status === 201) {
  431.             this.$store.dispatch('ppob/setMessage', `Product ${this.productName} successfully created`)
  432.             this.loading = false
  433.             this.$router.push(`/ppob-list/${this.$route.params.type}/detail/${this.$route.params.id}/products`)
  434.           } else {
  435.             this.snackbar = true
  436.             this.snackbarText = result.message
  437.             this.snackbarColor = 'error'
  438.             this.loading = false
  439.           }
  440.         }).catch(error => {
  441.           this.snackbar.value = true
  442.           this.snackbar.text = error.message
  443.           this.snackbar.color = 'error'
  444.           this.loading = false
  445.         })
  446.       } else if (this.mode === 'edit') {
  447.         let params = {
  448.           body: {
  449.             name: this.productName,
  450.             description: this.descriptionEditorContent,
  451.             price: this.sellingPrice,
  452.             vendors: this.paramsProductPricesForSubmit()
  453.           },
  454.           id: this.$route.params.id_products
  455.         }
  456.         this.loading = true
  457.         await this.$store.dispatch('ppob/editPPOBProduct', params).then(result => {
  458.           if (result.status === 200 || result.status === 201) {
  459.             this.$store.dispatch('ppob/setMessage', `Vendor ${this.vendorName} successfully updated`)
  460.             this.loading = false
  461.             this.$router.push(`/ppob-list/${this.$route.params.type}/detail/${this.$route.params.id}/products`)
  462.           } else {
  463.             this.snackbar = true
  464.             this.snackbarText = result.message
  465.             this.snackbarColor = 'error'
  466.             this.loading = false
  467.           }
  468.         }).catch(error => {
  469.           this.snackbar.value = true
  470.           this.snackbar.text = error.message
  471.           this.snackbar.color = 'error'
  472.           this.loading = false
  473.         })
  474.       }
  475.     },
  476.     autocompleteFilter (item, queryText, itemText) {
  477.       const actualItemName = item.name || item.category_name
  478.       const mainText = actualItemName.toLowerCase()
  479.       const searchText = queryText.toLowerCase()
  480.  
  481.       return mainText.indexOf(searchText) > -1
  482.     },
  483.     addNewProduct () {
  484.       this.productPrices.push({
  485.         vendorSelected: {},
  486.         vendorDetailProductSelected: {},
  487.         purchasePrice: 0,
  488.         priceStatus: true
  489.       })
  490.     },
  491.     removeNewProduct (targetId) {
  492.       this.productPrices = [
  493.         ...this.productPrices.filter((productPrice, index) => {
  494.           return index !== targetId
  495.         })
  496.       ]
  497.     },
  498.     removeProduct () {
  499.       this.productPrices.splice()
  500.     },
  501.     definePageTitle () {
  502.       if (this.$route.params.type === 'mobile_credit') this.pageTitle = 'Pulsa'
  503.       else if (this.$route.params.type === 'mobile_package') this.pageTitle = 'Paket Data'
  504.       else if (this.$route.params.type === 'prepaid_electricity') this.pageTitle = 'Listrik'
  505.     },
  506.     cancel () {
  507.       this.$router.push(`/ppob-list/${this.$route.params.type}/detail/${this.$route.params.id}/products`)
  508.     },
  509.     confirmModal () {
  510.       this.dialogConfirmation = true
  511.     },
  512.     idRules (idProduct) {
  513.       if (idProduct) {
  514.         return true
  515.       } else {
  516.         return 'This field is required'
  517.       }
  518.     },
  519.     async fetchPPOBVendors () {
  520.       this.loading = true
  521.       await this.$store.dispatch('ppob/fetchPPOBVendors').then(result => {
  522.         if (result.status === 200) {
  523.           this.$set(this, 'vendors', result.data)
  524.           this.loading = false
  525.         } else {
  526.           this.snackbar.value = true
  527.           this.snackbar.text = result.message
  528.           this.snackbar.color = 'error'
  529.           this.loading = false
  530.         }
  531.       }).catch(error => {
  532.         this.snackbar.value = true
  533.         this.snackbar.text = error.message
  534.         this.snackbar.color = 'error'
  535.         this.loading = false
  536.       })
  537.     },
  538.     async fetchProductIdVendor (vendorProductSelected, targetId = null) {
  539.       this.fetchVendorLoading = true
  540.       let params = {
  541.         idvendor: vendorProductSelected.id
  542.       }
  543.       await this.$store.dispatch('ppob/fetchPPOBVendorProducts', params).then(result => {
  544.         if (result.status === 200) {
  545.           if (targetId === null) {
  546.             this.$set(this, 'vendorDetailProducts', result.data)
  547.             this.loading = false
  548.             return
  549.           }
  550.           this.$set(this.productPrices[targetId], 'vendorDetailProducts', result.data)
  551.           this.loading = false
  552.         } else {
  553.           this.snackbar.value = true
  554.           this.snackbar.text = result.message
  555.           this.snackbar.color = 'error'
  556.           this.loading = false
  557.         }
  558.         this.fetchVendorLoading = false
  559.       }).catch(error => {
  560.         this.snackbar.value = true
  561.         this.snackbar.text = error.message
  562.         this.snackbar.color = 'error'
  563.         this.loading = false
  564.       })
  565.     }
  566.   }
  567. }
  568. </script>
  569.  

Editor

You can edit this paste and save as new:


File Description
  • ppob.vue
  • Paste Code
  • 15 Jun-2021
  • 22.52 Kb
You can Share it: