AddEditPackageDialog.vue 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. <template>
  2. <q-dialog ref="dialogRef" @hide="onDialogHide">
  3. <div style="width: 100%; max-width: 700px">
  4. <q-card class="overflow-hidden" style="width: 100%">
  5. <q-btn
  6. flat
  7. round
  8. dense
  9. icon="mdi-close"
  10. class="absolute-top-right q-ma-sm"
  11. style="z-index: 1"
  12. @click="onDialogCancel"
  13. />
  14. <q-form ref="formRef" @submit="onOKClick">
  15. <q-card-section class="q-pt-lg">
  16. <div class="row q-col-gutter-sm">
  17. <DefaultInput
  18. v-model="form.name"
  19. label="Nome do Pacote"
  20. class="col-12"
  21. />
  22. <DefaultInput
  23. v-model="form.quantity_classes"
  24. label="Quantidade de Aulas"
  25. class="col-12"
  26. type="number"
  27. />
  28. <DefaultCurrencyInput
  29. v-model="form.contract_register_value"
  30. label="R$ Matrícula"
  31. class="col-4"
  32. />
  33. <DefaultCurrencyInput
  34. v-model="form.contract_value"
  35. label="R$ Total do Contrato"
  36. class="col-4"
  37. />
  38. <DefaultInput
  39. v-model="form.contrat_discount_value"
  40. label="Desconto em %"
  41. class="col-4"
  42. type="number"
  43. min="0"
  44. max="100"
  45. />
  46. <div
  47. v-for="(material, index) in form.materials"
  48. :key="index"
  49. class="col-12"
  50. >
  51. <div class="row q-col-gutter-sm items-center">
  52. <DefaultSelect
  53. v-model="material.product_id"
  54. label="Material"
  55. class="col"
  56. :options="productOptions"
  57. emit-value
  58. map-options
  59. @update:model-value="onProductSelected(material)"
  60. />
  61. <DefaultInput
  62. v-model="material.quantity"
  63. label="Qtd"
  64. class="col-2"
  65. type="number"
  66. min="1"
  67. />
  68. <DefaultCurrencyInput
  69. v-model="material.price"
  70. label="R$ Unitário"
  71. class="col-3"
  72. />
  73. <div class="col-auto">
  74. <q-btn
  75. v-if="index === form.materials.length - 1"
  76. color="primary"
  77. icon="mdi-plus"
  78. unelevated
  79. style="border-radius: 8px; height: 40px; width: 40px"
  80. @click="addMaterial"
  81. />
  82. <q-btn
  83. v-else
  84. flat
  85. round
  86. dense
  87. icon="mdi-delete-outline"
  88. color="negative"
  89. @click="removeMaterial(index)"
  90. />
  91. </div>
  92. </div>
  93. </div>
  94. </div>
  95. </q-card-section>
  96. <q-card-actions align="right" class="q-px-md q-pb-md">
  97. <q-btn
  98. outline
  99. color="primary"
  100. label="Cancelar"
  101. @click="onDialogCancel"
  102. />
  103. <q-btn
  104. color="primary"
  105. label="Salvar"
  106. type="submit"
  107. :loading="loading"
  108. />
  109. </q-card-actions>
  110. </q-form>
  111. </q-card>
  112. </div>
  113. </q-dialog>
  114. </template>
  115. <script setup>
  116. import { ref, computed, onMounted } from "vue";
  117. import { useDialogPluginComponent } from "quasar";
  118. import DefaultInput from "src/components/defaults/DefaultInput.vue";
  119. import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
  120. import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
  121. import {
  122. getUnitPackage,
  123. createUnitPackage,
  124. updateUnitPackage,
  125. } from "src/api/package";
  126. import { getProductsForSelect } from "src/api/product";
  127. defineEmits([...useDialogPluginComponent.emits]);
  128. const props = defineProps({
  129. package: {
  130. type: Object,
  131. default: null,
  132. },
  133. });
  134. const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
  135. useDialogPluginComponent();
  136. const formRef = ref(null);
  137. const loading = ref(false);
  138. const products = ref([]);
  139. const productOptions = computed(() =>
  140. products.value.map((p) => ({
  141. label: p.name,
  142. value: p.id,
  143. price_sale: p.price_sale,
  144. })),
  145. );
  146. const form = ref({
  147. name: props.package?.name ?? null,
  148. quantity_classes: props.package?.quantity_classes ?? null,
  149. contract_register_value: props.package?.contract_register_value ?? null,
  150. contract_value: props.package?.contract_value ?? null,
  151. contrat_discount_value: props.package?.contrat_discount_value ?? null,
  152. materials: [{ product_id: null, quantity: 1, price: null }],
  153. });
  154. const onProductSelected = (material) => {
  155. const option = productOptions.value.find(
  156. (o) => o.value === material.product_id,
  157. );
  158. if (option) material.price = option.price_sale;
  159. };
  160. const addMaterial = () => {
  161. form.value.materials.push({ product_id: null, quantity: 1, price: null });
  162. };
  163. const removeMaterial = (index) => {
  164. form.value.materials.splice(index, 1);
  165. };
  166. onMounted(async () => {
  167. const [allProducts] = await Promise.all([getProductsForSelect()]);
  168. products.value = allProducts;
  169. if (props.package?.id) {
  170. const pkg = await getUnitPackage(props.package.id);
  171. if (pkg.materials?.length) {
  172. form.value.materials = pkg.materials.map((m) => ({
  173. product_id: m.product_id,
  174. quantity: m.quantity,
  175. price: m.price,
  176. }));
  177. }
  178. }
  179. });
  180. const onOKClick = async () => {
  181. loading.value = true;
  182. try {
  183. const validMaterials = form.value.materials.filter((m) => m.product_id);
  184. const payload = {
  185. name: form.value.name,
  186. quantity_classes: form.value.quantity_classes,
  187. contract_value: form.value.contract_value,
  188. contract_register_value: form.value.contract_register_value,
  189. contrat_discount_value: form.value.contrat_discount_value,
  190. materials: validMaterials.map((m) => ({
  191. product_id: m.product_id,
  192. quantity: Number(m.quantity),
  193. price: Number(m.price),
  194. })),
  195. };
  196. const result = props.package?.id
  197. ? await updateUnitPackage(props.package.id, payload)
  198. : await createUnitPackage(payload);
  199. onDialogOK(result);
  200. } finally {
  201. loading.value = false;
  202. }
  203. };
  204. </script>