|
|
@@ -1,5 +1,13 @@
|
|
|
<template>
|
|
|
<div>
|
|
|
+ <input
|
|
|
+ ref="signedFileInputRef"
|
|
|
+ accept="image/jpeg,image/png,.pdf"
|
|
|
+ style="display: none"
|
|
|
+ type="file"
|
|
|
+ @change="onSignedFileSelected"
|
|
|
+ />
|
|
|
+
|
|
|
<DefaultHeaderPage title="Contratos" />
|
|
|
|
|
|
<div class="q-px-sm">
|
|
|
@@ -100,65 +108,127 @@
|
|
|
</q-btn>
|
|
|
|
|
|
<q-btn
|
|
|
- v-if="row.file_url || canEdit"
|
|
|
- :icon="
|
|
|
- row.file_url
|
|
|
- ? 'mdi-file-eye-outline'
|
|
|
- : 'mdi-file-plus-outline'
|
|
|
- "
|
|
|
- :loading="generatingId === row.id"
|
|
|
- outline
|
|
|
- style="width: 36px"
|
|
|
- @click.prevent.stop="handleContractFile(row)"
|
|
|
- >
|
|
|
- <q-tooltip>
|
|
|
- {{
|
|
|
- row.file_url
|
|
|
- ? "Visualizar arquivo do contrato"
|
|
|
- : "Gerar arquivo do contrato"
|
|
|
- }}
|
|
|
- </q-tooltip>
|
|
|
- </q-btn>
|
|
|
-
|
|
|
- <q-btn
|
|
|
- v-if="canEdit"
|
|
|
+ v-if="canEdit || row.file_url || row.signed_file_url"
|
|
|
icon="mdi-dots-vertical"
|
|
|
outline
|
|
|
style="width: 36px"
|
|
|
@click.prevent.stop
|
|
|
>
|
|
|
<q-menu>
|
|
|
- <q-list style="min-width: 170px">
|
|
|
- <template
|
|
|
- v-if="
|
|
|
- row.status === 'frozen' || row.status === 'cancelled'
|
|
|
- "
|
|
|
- >
|
|
|
+ <q-list style="min-width: 280px">
|
|
|
<q-item
|
|
|
+ v-if="row.file_url || canEdit"
|
|
|
v-close-popup
|
|
|
+ class="q-pa-md"
|
|
|
clickable
|
|
|
- @click="handleReactivate(row)"
|
|
|
+ @click="handleContractFile(row)"
|
|
|
>
|
|
|
- <q-item-section> Reativar Contrato </q-item-section>
|
|
|
+ <q-item-section avatar>
|
|
|
+ <q-spinner
|
|
|
+ v-if="generatingId === row.id"
|
|
|
+ color="primary"
|
|
|
+ size="20px"
|
|
|
+ />
|
|
|
+
|
|
|
+ <q-icon
|
|
|
+ v-else
|
|
|
+ :name="
|
|
|
+ row.file_url
|
|
|
+ ? 'mdi-file-eye-outline'
|
|
|
+ : 'mdi-file-plus-outline'
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </q-item-section>
|
|
|
+
|
|
|
+ <q-item-section>
|
|
|
+ {{
|
|
|
+ row.file_url
|
|
|
+ ? "Visualizar arquivo do contrato"
|
|
|
+ : "Gerar arquivo do contrato"
|
|
|
+ }}
|
|
|
+ </q-item-section>
|
|
|
</q-item>
|
|
|
- </template>
|
|
|
|
|
|
- <template v-else>
|
|
|
<q-item
|
|
|
+ v-if="row.signed_file_url || canEdit"
|
|
|
v-close-popup
|
|
|
+ class="q-pa-md"
|
|
|
clickable
|
|
|
- @click="handleFreeze(row)"
|
|
|
+ @click="handleSignedContractFile(row)"
|
|
|
>
|
|
|
- <q-item-section> Trancar Contrato </q-item-section>
|
|
|
+ <q-item-section avatar>
|
|
|
+ <q-spinner
|
|
|
+ v-if="uploadingSignedId === row.id"
|
|
|
+ color="primary"
|
|
|
+ size="20px"
|
|
|
+ />
|
|
|
+
|
|
|
+ <q-icon
|
|
|
+ v-else
|
|
|
+ :name="
|
|
|
+ row.signed_file_url
|
|
|
+ ? 'mdi-file-check-outline'
|
|
|
+ : 'mdi-file-upload-outline'
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </q-item-section>
|
|
|
+
|
|
|
+ <q-item-section>
|
|
|
+ {{
|
|
|
+ row.signed_file_url
|
|
|
+ ? "Visualizar contrato assinado"
|
|
|
+ : "Enviar contrato assinado"
|
|
|
+ }}
|
|
|
+ </q-item-section>
|
|
|
</q-item>
|
|
|
|
|
|
- <q-item
|
|
|
- v-close-popup
|
|
|
- clickable
|
|
|
- @click="handleCancel(row)"
|
|
|
+ <template
|
|
|
+ v-if="
|
|
|
+ canEdit &&
|
|
|
+ (row.status === 'frozen' ||
|
|
|
+ row.status === 'cancelled')
|
|
|
+ "
|
|
|
>
|
|
|
- <q-item-section> Cancelar Contrato </q-item-section>
|
|
|
- </q-item>
|
|
|
+ <q-item
|
|
|
+ v-close-popup
|
|
|
+ class="q-pa-md"
|
|
|
+ clickable
|
|
|
+ @click="handleReactivate(row)"
|
|
|
+ >
|
|
|
+ <q-item-section avatar>
|
|
|
+ <q-icon name="mdi-refresh" />
|
|
|
+ </q-item-section>
|
|
|
+
|
|
|
+ <q-item-section> Reativar Contrato </q-item-section>
|
|
|
+ </q-item>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-else-if="canEdit">
|
|
|
+ <q-item
|
|
|
+ v-close-popup
|
|
|
+ class="q-pa-md"
|
|
|
+ clickable
|
|
|
+ @click="handleFreeze(row)"
|
|
|
+ >
|
|
|
+ <q-item-section avatar>
|
|
|
+ <q-icon name="mdi-file-cancel-outline" />
|
|
|
+ </q-item-section>
|
|
|
+
|
|
|
+ <q-item-section> Trancar Contrato </q-item-section>
|
|
|
+ </q-item>
|
|
|
+
|
|
|
+ <q-item
|
|
|
+ v-close-popup
|
|
|
+ class="q-pa-md"
|
|
|
+ clickable
|
|
|
+ @click="handleCancel(row)"
|
|
|
+ >
|
|
|
+ <q-item-section avatar>
|
|
|
+ <q-icon name="mdi-file-cancel-outline" />
|
|
|
+ </q-item-section>
|
|
|
+
|
|
|
+ <q-item-section> Cancelar Contrato </q-item-section>
|
|
|
+ </q-item>
|
|
|
</template>
|
|
|
</q-list>
|
|
|
</q-menu>
|
|
|
@@ -173,6 +243,7 @@
|
|
|
|
|
|
<script setup>
|
|
|
import {
|
|
|
+ attachSignedContractFile,
|
|
|
cancelContract,
|
|
|
generateStudentContractFile,
|
|
|
getAllContracts,
|
|
|
@@ -202,6 +273,8 @@ const permissions = permissionStore();
|
|
|
|
|
|
const isLoading = ref(false);
|
|
|
const generatingId = ref(null);
|
|
|
+const signedFileInputRef = ref(null);
|
|
|
+const uploadingSignedId = ref(null);
|
|
|
const rows = ref([]);
|
|
|
|
|
|
const canEdit = computed(() =>
|
|
|
@@ -247,6 +320,8 @@ const columns = [
|
|
|
},
|
|
|
];
|
|
|
|
|
|
+let pendingSignedContractId = null;
|
|
|
+
|
|
|
const confirmAction = (title, message, apiFunction, contract) => {
|
|
|
$q.dialog({
|
|
|
component: ContractActionConfirmDialog,
|
|
|
@@ -323,6 +398,8 @@ const handleHistory = (contract) => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
+//
|
|
|
+
|
|
|
const handleContractFile = async (contract) => {
|
|
|
if (contract.file_url) {
|
|
|
window.open(contract.file_url, "_blank", "noopener,noreferrer");
|
|
|
@@ -367,6 +444,65 @@ const handleContractFile = async (contract) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+//
|
|
|
+
|
|
|
+const handleSignedContractFile = (contract) => {
|
|
|
+ if (contract.signed_file_url) {
|
|
|
+ window.open(contract.signed_file_url, "_blank", "noopener,noreferrer");
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ pendingSignedContractId = contract.id;
|
|
|
+
|
|
|
+ signedFileInputRef.value.value = "";
|
|
|
+ signedFileInputRef.value.click();
|
|
|
+};
|
|
|
+
|
|
|
+const onSignedFileSelected = async (event) => {
|
|
|
+ const file = event.target.files?.[0];
|
|
|
+
|
|
|
+ const contractId = pendingSignedContractId;
|
|
|
+
|
|
|
+ if (!file || !contractId) return;
|
|
|
+
|
|
|
+ uploadingSignedId.value = contractId;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const formData = new FormData();
|
|
|
+
|
|
|
+ formData.append("file", file);
|
|
|
+
|
|
|
+ const updated = await attachSignedContractFile(contractId, formData);
|
|
|
+
|
|
|
+ const index = rows.value.findIndex((row) => row.id === contractId);
|
|
|
+
|
|
|
+ if (index !== -1) {
|
|
|
+ rows.value[index] = {
|
|
|
+ ...rows.value[index],
|
|
|
+ ...updated,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ $q.notify({
|
|
|
+ message: "Contrato assinado enviado com sucesso.",
|
|
|
+ type: "positive",
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+
|
|
|
+ $q.notify({
|
|
|
+ message: "Erro ao enviar o contrato assinado.",
|
|
|
+ type: "negative",
|
|
|
+ });
|
|
|
+ } finally {
|
|
|
+ pendingSignedContractId = null;
|
|
|
+ uploadingSignedId.value = null;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+//
|
|
|
+
|
|
|
const handleReactivate = (contract) => {
|
|
|
confirmAction(
|
|
|
"Reativar Contrato",
|