ViewContractDialog.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <template>
  2. <q-dialog ref="dialogRef" @hide="onDialogHide">
  3. <q-card
  4. class="q-dialog-plugin overflow-hidden"
  5. style="width: 100%; max-width: 1350px"
  6. >
  7. <DefaultDialogHeader
  8. title="Visualizar Contrato"
  9. @close="onDialogCancel"
  10. />
  11. <template v-if="loading">
  12. <q-card-section
  13. class="flex flex-center"
  14. style="height: 65vh"
  15. >
  16. <q-spinner
  17. color="primary"
  18. size="40px"
  19. />
  20. </q-card-section>
  21. </template>
  22. <template v-else-if="contract">
  23. <q-tabs
  24. v-model="activeTab"
  25. active-color="primary"
  26. align="left"
  27. class="q-px-md text-grey-7"
  28. dense
  29. indicator-color="primary"
  30. >
  31. <q-tab
  32. label="Dados do Contrato"
  33. name="dados"
  34. />
  35. <q-tab
  36. label="Mídias do Contrato"
  37. name="midias"
  38. />
  39. </q-tabs>
  40. <q-separator />
  41. <q-card-section
  42. class="q-pt-sm"
  43. style="height: 65vh; overflow-y: auto"
  44. >
  45. <div v-show="activeTab === 'dados'">
  46. <div class="text-subtitle1 q-mb-md">
  47. Dados do Aluno
  48. </div>
  49. <div class="row q-col-gutter-sm">
  50. <div class="col-12">
  51. <DefaultInput
  52. :model-value="contract.student_name"
  53. disable
  54. label="Aluno"
  55. />
  56. </div>
  57. <div class="col-6">
  58. <DefaultInput
  59. :model-value="contract.student_document"
  60. :mask="masks.Brasil.cpf"
  61. :rules="[inputRules.cpf]"
  62. disable
  63. label="CPF"
  64. />
  65. </div>
  66. <div class="col-6">
  67. <DefaultInput
  68. :model-value="contract.student_birth_date"
  69. disable
  70. label="Data de Nascimento"
  71. />
  72. </div>
  73. </div>
  74. <div class="text-subtitle1 q-mt-lg q-mb-md">
  75. Dados do Contrato
  76. </div>
  77. <div class="row q-col-gutter-sm">
  78. <div class="col-4">
  79. <DefaultInput
  80. :model-value="contract.protocol"
  81. disable
  82. label="Protocolo"
  83. />
  84. </div>
  85. <div class="col-4">
  86. <DefaultInput
  87. :model-value="contract.signature_date"
  88. disable
  89. label="Data Assinatura"
  90. />
  91. </div>
  92. <div class="col-4">
  93. <DefaultInput
  94. :model-value="contract.end_date"
  95. disable
  96. label="Data Encerramento"
  97. />
  98. </div>
  99. <div class="col-5">
  100. <DefaultInput
  101. :model-value="contract.package_name"
  102. disable
  103. label="Pacote de Aulas"
  104. />
  105. </div>
  106. <div class="col-7">
  107. <DefaultInput
  108. :model-value="contract.class_quantity"
  109. disable
  110. label="Qtd. Aulas"
  111. />
  112. </div>
  113. <div class="col-6">
  114. <DefaultCurrencyInput
  115. :model-value="contract.package_value"
  116. disable
  117. label="Total do Contrato"
  118. />
  119. </div>
  120. <div class="col-6">
  121. <DefaultInput
  122. :model-value="contractWeeks"
  123. disable
  124. label="Total de Semanas"
  125. />
  126. </div>
  127. <div class="col-4">
  128. <DefaultInput
  129. :model-value="weekdayLabel(contract.weekday)"
  130. disable
  131. label="Dia da Semana"
  132. />
  133. </div>
  134. <div class="col-4">
  135. <DefaultInput
  136. :model-value="contract.start_time"
  137. disable
  138. label="Hora de Início"
  139. >
  140. <template #append>
  141. <q-icon name="mdi-clock-outline" />
  142. </template>
  143. </DefaultInput>
  144. </div>
  145. <div class="col-4">
  146. <DefaultInput
  147. :model-value="contract.end_time"
  148. disable
  149. label="Hora de Término"
  150. >
  151. <template #append>
  152. <q-icon name="mdi-clock-outline" />
  153. </template>
  154. </DefaultInput>
  155. </div>
  156. <div class="col-4">
  157. <DefaultInput
  158. :model-value="weekdayLabel(contract.second_weekday)"
  159. disable
  160. label="2° Dia da Semana"
  161. />
  162. </div>
  163. <div class="col-4">
  164. <DefaultInput
  165. :model-value="contract.second_start_time"
  166. disable
  167. label="Hora de Início"
  168. >
  169. <template #append>
  170. <q-icon name="mdi-clock-outline" />
  171. </template>
  172. </DefaultInput>
  173. </div>
  174. <div class="col-4">
  175. <DefaultInput
  176. :model-value="contract.second_end_time"
  177. disable
  178. label="Hora de Término"
  179. >
  180. <template #append>
  181. <q-icon name="mdi-clock-outline" />
  182. </template>
  183. </DefaultInput>
  184. </div>
  185. </div>
  186. <div class="text-subtitle1 q-mt-lg q-mb-md">
  187. Dados Financeiros
  188. </div>
  189. <div class="row q-col-gutter-sm">
  190. <div class="col-4">
  191. <DefaultInput
  192. :model-value="contract.due_day"
  193. disable
  194. label="Dia de Vencimento"
  195. />
  196. </div>
  197. <div class="col-4">
  198. <DefaultCurrencyInput
  199. :model-value="contract.tax_register"
  200. disable
  201. label="Taxa de Matrícula"
  202. />
  203. </div>
  204. <div class="col-4">
  205. <DefaultInput
  206. :model-value="contract.class_quantity"
  207. disable
  208. label="Total de Aulas"
  209. />
  210. </div>
  211. <div class="col-3">
  212. <DefaultCurrencyInput
  213. :model-value="contract.down_payment"
  214. disable
  215. label="Entrada"
  216. />
  217. </div>
  218. <div class="col-3">
  219. <DefaultInput
  220. :model-value="
  221. contract.installments
  222. ? `${contract.installments}x`
  223. : null
  224. "
  225. disable
  226. label="Parcelas"
  227. />
  228. </div>
  229. <div class="col-6">
  230. <DefaultInput
  231. :model-value="contract.early_payment_discount"
  232. disable
  233. label="Desconto até o vencimento (%)"
  234. />
  235. </div>
  236. <div class="col-3">
  237. <DefaultCurrencyInput
  238. :model-value="contract.material_value"
  239. disable
  240. label="Valor dos Materiais"
  241. />
  242. </div>
  243. <div class="col-3">
  244. <DefaultInput
  245. :model-value="
  246. contract.material_installments
  247. ? `${contract.material_installments}x`
  248. : null
  249. "
  250. disable
  251. label="Parcelas"
  252. />
  253. </div>
  254. <div class="col-6">
  255. <DefaultInput
  256. :model-value="contract.interest_rate"
  257. disable
  258. label="Juros (%) a.m"
  259. />
  260. </div>
  261. <div class="col-6">
  262. <DefaultInput
  263. :model-value="
  264. paymentMethodLabel(contract.payment_method)
  265. "
  266. disable
  267. label="Forma de Pagamento"
  268. />
  269. </div>
  270. <div class="col-6">
  271. <DefaultInput
  272. :model-value="contract.fine_cancelled"
  273. disable
  274. label="Multa (%)"
  275. />
  276. </div>
  277. </div>
  278. </div>
  279. <div v-show="activeTab === 'midias'">
  280. <DefaultTable
  281. v-model:rows="medias"
  282. :columns="mediaColumns"
  283. :feminino="true"
  284. :loading="loadingMedias"
  285. :show-search-field="false"
  286. descricao="mídias"
  287. no-api-call
  288. title="Mídias"
  289. >
  290. <template #body-cell-actions="{ row }">
  291. <q-td align="center">
  292. <q-btn
  293. icon="mdi-eye-outline"
  294. outline
  295. style="width: 36px"
  296. @click.prevent.stop="openFile(row.file_url)"
  297. />
  298. </q-td>
  299. </template>
  300. </DefaultTable>
  301. </div>
  302. </q-card-section>
  303. </template>
  304. <q-card-actions
  305. align="right"
  306. class="q-px-md q-pb-md"
  307. >
  308. <q-btn
  309. color="primary"
  310. label="Fechar"
  311. no-caps
  312. outline
  313. @click="onDialogCancel"
  314. />
  315. </q-card-actions>
  316. </q-card>
  317. </q-dialog>
  318. </template>
  319. <script setup>
  320. import { computed, onMounted, ref, watch } from "vue";
  321. import {
  322. differenceInCalendarDays,
  323. isValid,
  324. parse,
  325. } from "date-fns";
  326. import { getContractMedias } from "src/api/student_media";
  327. import { getStudentContractById } from "src/api/studentContract";
  328. import { useDialogPluginComponent } from "quasar";
  329. import { useInputRules } from "src/composables/useInputRules";
  330. import masks from "src/helpers/masks";
  331. import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
  332. import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
  333. import DefaultInput from "src/components/defaults/DefaultInput.vue";
  334. import DefaultTable from "src/components/defaults/DefaultTable.vue";
  335. defineEmits([...useDialogPluginComponent.emits]);
  336. const props = defineProps({
  337. id: {
  338. type: Number,
  339. required: true,
  340. },
  341. });
  342. const { dialogRef, onDialogHide, onDialogCancel } =
  343. useDialogPluginComponent();
  344. const { inputRules } = useInputRules();
  345. const activeTab = ref("dados");
  346. const contract = ref(null);
  347. const loading = ref(false);
  348. const loadingMedias = ref(false);
  349. const medias = ref([]);
  350. const contractWeeks = computed(() => {
  351. if (!contract.value?.signature_date || !contract.value?.end_date) {
  352. return null;
  353. }
  354. const startDate = parse(
  355. contract.value.signature_date,
  356. "dd/MM/yyyy",
  357. new Date(),
  358. );
  359. const endDate = parse(
  360. contract.value.end_date,
  361. "dd/MM/yyyy",
  362. new Date(),
  363. );
  364. if (!isValid(startDate) || !isValid(endDate)) {
  365. return null;
  366. }
  367. const days = differenceInCalendarDays(
  368. endDate,
  369. startDate,
  370. );
  371. return days < 0
  372. ? null
  373. : Math.max(1, Math.round(days / 7));
  374. });
  375. const mediaColumns = [
  376. {
  377. align: "left",
  378. field: "created_at",
  379. label: "Data de Anexo",
  380. name: "created_at",
  381. },
  382. {
  383. align: "center",
  384. field: null,
  385. label: "Ações",
  386. name: "actions",
  387. },
  388. ];
  389. const paymentMethods = {
  390. credit_card: "Cartão de Crédito",
  391. debit_card: "Cartão de Débito",
  392. pix: "Pix",
  393. };
  394. const weekdays = {
  395. 0: "Domingo",
  396. 1: "Segunda",
  397. 2: "Terça",
  398. 3: "Quarta",
  399. 4: "Quinta",
  400. 5: "Sexta",
  401. 6: "Sábado",
  402. };
  403. const fetchMedias = async () => {
  404. loadingMedias.value = true;
  405. try {
  406. medias.value = await getContractMedias(props.id);
  407. } finally {
  408. loadingMedias.value = false;
  409. }
  410. };
  411. const openFile = (url) => {
  412. window.open(url, "_blank");
  413. };
  414. const paymentMethodLabel = (value) =>
  415. value ? paymentMethods[value] ?? value : null;
  416. const weekdayLabel = (value) =>
  417. value != null ? weekdays[value] ?? null : null;
  418. watch(activeTab, (tab) => {
  419. if (tab === "midias") {
  420. fetchMedias();
  421. }
  422. });
  423. onMounted(async () => {
  424. loading.value = true;
  425. try {
  426. contract.value = await getStudentContractById(
  427. props.id,
  428. );
  429. } finally {
  430. loading.value = false;
  431. }
  432. });
  433. </script>