|
@@ -1,135 +1,47 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div>
|
|
<div>
|
|
|
- <q-form ref="formRef" @submit="onSave">
|
|
|
|
|
- <div class="row q-col-gutter-sm">
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.name"
|
|
|
|
|
- label="Nome"
|
|
|
|
|
- class="col-6"
|
|
|
|
|
- :rules="[inputRules.required]"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.degree"
|
|
|
|
|
- label="Grau de Parentesco"
|
|
|
|
|
- class="col-6"
|
|
|
|
|
- :rules="[inputRules.required]"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInputDatePicker
|
|
|
|
|
- v-model="form.birth_date"
|
|
|
|
|
- label="Data de Nascimento"
|
|
|
|
|
- class="col-4"
|
|
|
|
|
- :rules="[inputRules.required]"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.cpf"
|
|
|
|
|
- label="CPF"
|
|
|
|
|
- class="col-4"
|
|
|
|
|
- :mask="masks.Brasil.cpf"
|
|
|
|
|
- :rules="[inputRules.required]"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultSelect
|
|
|
|
|
- v-model="form.gender"
|
|
|
|
|
- label="Gênero"
|
|
|
|
|
- class="col-4"
|
|
|
|
|
- emit-value
|
|
|
|
|
- map-options
|
|
|
|
|
- :options="genderOptions"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.email"
|
|
|
|
|
- label="E-mail"
|
|
|
|
|
- class="col-6"
|
|
|
|
|
- type="email"
|
|
|
|
|
- :rules="[inputRules.email]"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.phone"
|
|
|
|
|
- label="Telefone"
|
|
|
|
|
- class="col-6"
|
|
|
|
|
- :mask="masks.Brasil.celular"
|
|
|
|
|
- :rules="[inputRules.required]"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultCepInput
|
|
|
|
|
- v-model="form.postal_code"
|
|
|
|
|
- class="col-4"
|
|
|
|
|
- @rua="(v) => (form.street = v)"
|
|
|
|
|
- @bairro="(v) => (form.neighborhood = v)"
|
|
|
|
|
- @uf="(v) => stateSelectRef?.selectStateByCode(v)"
|
|
|
|
|
- @cidade="(v) => citySelectRef?.selectCityByName(v)"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.street"
|
|
|
|
|
- label="Endereço"
|
|
|
|
|
- class="col-5"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.address_number"
|
|
|
|
|
- label="Número"
|
|
|
|
|
- class="col-3"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.neighborhood"
|
|
|
|
|
- label="Bairro"
|
|
|
|
|
- class="col-4"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <CitySelect
|
|
|
|
|
- ref="citySelectRef"
|
|
|
|
|
- v-model="selectedCity"
|
|
|
|
|
- label="Cidade"
|
|
|
|
|
- class="col-4"
|
|
|
|
|
- :state="selectedState"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <StateSelect
|
|
|
|
|
- ref="stateSelectRef"
|
|
|
|
|
- v-model="selectedState"
|
|
|
|
|
- label="Estado"
|
|
|
|
|
- class="col-4"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.complement"
|
|
|
|
|
- label="Complemento"
|
|
|
|
|
- class="col-12"
|
|
|
|
|
- />
|
|
|
|
|
-
|
|
|
|
|
- <DefaultInput
|
|
|
|
|
- v-model="form.notes"
|
|
|
|
|
- label="Observações"
|
|
|
|
|
- class="col-12"
|
|
|
|
|
- type="textarea"
|
|
|
|
|
- :input-style="{ minHeight: '120px' }"
|
|
|
|
|
- autogrow
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- </q-form>
|
|
|
|
|
|
|
+ <DefaultTable
|
|
|
|
|
+ v-model:rows="rows"
|
|
|
|
|
+ title="Responsáveis"
|
|
|
|
|
+ :columns
|
|
|
|
|
+ descricao="responsáveis"
|
|
|
|
|
+ :feminino="true"
|
|
|
|
|
+ no-api-call
|
|
|
|
|
+ add-item
|
|
|
|
|
+ :show-search-field="false"
|
|
|
|
|
+ @on-add-item="handleAdd"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #body-cell-actions="{ row }">
|
|
|
|
|
+ <q-td align="center">
|
|
|
|
|
+ <q-item-section class="no-wrap" style="flex-direction: row; gap: 4px">
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ outline
|
|
|
|
|
+ icon="mdi-pencil-outline"
|
|
|
|
|
+ style="width: 36px"
|
|
|
|
|
+ @click.prevent.stop="handleEdit(row)"
|
|
|
|
|
+ />
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ outline
|
|
|
|
|
+ icon="mdi-trash-can-outline"
|
|
|
|
|
+ style="width: 36px"
|
|
|
|
|
+ @click.prevent.stop="handleDelete(row)"
|
|
|
|
|
+ />
|
|
|
|
|
+ </q-item-section>
|
|
|
|
|
+ </q-td>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </DefaultTable>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { ref, watch, onMounted, useTemplateRef } from "vue";
|
|
|
|
|
-import DefaultInput from "src/components/defaults/DefaultInput.vue";
|
|
|
|
|
-import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
|
|
|
|
|
-import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
|
|
|
|
|
-import DefaultCepInput from "src/components/defaults/DefaultCepInput.vue";
|
|
|
|
|
-import CitySelect from "src/components/selects/CitySelect.vue";
|
|
|
|
|
-import StateSelect from "src/components/selects/StateSelect.vue";
|
|
|
|
|
-import { useInputRules } from "src/composables/useInputRules";
|
|
|
|
|
-import { getStudentResponsible } from "src/api/studentResponsible";
|
|
|
|
|
-import masks from "src/helpers/masks";
|
|
|
|
|
-import { formatDateYMDtoDMY, formatDateDMYtoYMD } from "src/helpers/utils";
|
|
|
|
|
|
|
+import { ref, onMounted } from "vue";
|
|
|
|
|
+import { useQuasar } from "quasar";
|
|
|
|
|
+import DefaultTable from "src/components/defaults/DefaultTable.vue";
|
|
|
|
|
+import ResponsibleDialog from "src/pages/students/components/ResponsibleDialog.vue";
|
|
|
|
|
+import {
|
|
|
|
|
+ getStudentResponsible,
|
|
|
|
|
+ deleteStudentResponsible,
|
|
|
|
|
+} from "src/api/studentResponsible";
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
|
studentId: {
|
|
studentId: {
|
|
@@ -138,109 +50,57 @@ const props = defineProps({
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-const { inputRules } = useInputRules();
|
|
|
|
|
-const formRef = useTemplateRef("formRef");
|
|
|
|
|
-const stateSelectRef = useTemplateRef("stateSelectRef");
|
|
|
|
|
-const citySelectRef = useTemplateRef("citySelectRef");
|
|
|
|
|
|
|
+const $q = useQuasar();
|
|
|
|
|
+const rows = ref([]);
|
|
|
|
|
|
|
|
-const selectedState = ref(null);
|
|
|
|
|
-const selectedCity = ref(null);
|
|
|
|
|
-
|
|
|
|
|
-const genderOptions = [
|
|
|
|
|
- { label: "Masculino", value: "male" },
|
|
|
|
|
- { label: "Feminino", value: "female" },
|
|
|
|
|
- { label: "Outro", value: "other" },
|
|
|
|
|
- { label: "Prefiro não informar", value: "no_preference" },
|
|
|
|
|
-];
|
|
|
|
|
-
|
|
|
|
|
-const emptyForm = () => ({
|
|
|
|
|
- name: null,
|
|
|
|
|
- birth_date: null,
|
|
|
|
|
- cpf: null,
|
|
|
|
|
- gender: "no_preference",
|
|
|
|
|
- degree: null,
|
|
|
|
|
- email: null,
|
|
|
|
|
- phone: null,
|
|
|
|
|
- postal_code: null,
|
|
|
|
|
- street: null,
|
|
|
|
|
- address_number: null,
|
|
|
|
|
- neighborhood: null,
|
|
|
|
|
- state_id: null,
|
|
|
|
|
- city_id: null,
|
|
|
|
|
- complement: null,
|
|
|
|
|
- notes: null,
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-const form = ref(emptyForm());
|
|
|
|
|
-
|
|
|
|
|
-watch(selectedState, (state) => {
|
|
|
|
|
- form.value.state_id = state?.value ?? null;
|
|
|
|
|
-});
|
|
|
|
|
|
|
+const columns = ref([
|
|
|
|
|
+ { name: "name", label: "Nome", field: "name", align: "left" },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: "degree",
|
|
|
|
|
+ label: "Grau de Parentesco",
|
|
|
|
|
+ field: "degree",
|
|
|
|
|
+ align: "left",
|
|
|
|
|
+ },
|
|
|
|
|
+ { name: "phone", label: "Telefone", field: "phone", align: "left" },
|
|
|
|
|
+ { name: "email", label: "E-mail", field: "email", align: "left" },
|
|
|
|
|
+ { name: "actions", label: "Ações", field: null, align: "center" },
|
|
|
|
|
+]);
|
|
|
|
|
|
|
|
-watch(selectedCity, (city) => {
|
|
|
|
|
- form.value.city_id = city?.value ?? null;
|
|
|
|
|
-});
|
|
|
|
|
|
|
+async function loadResponsibles() {
|
|
|
|
|
+ rows.value = await getStudentResponsible(props.studentId);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-async function loadResponsible() {
|
|
|
|
|
- try {
|
|
|
|
|
- const data = await getStudentResponsible(props.studentId);
|
|
|
|
|
- if (data) {
|
|
|
|
|
- form.value = {
|
|
|
|
|
- name: data.name ?? null,
|
|
|
|
|
- birth_date: data.birth_date ? formatDateYMDtoDMY(data.birth_date) : null,
|
|
|
|
|
- cpf: data.cpf ?? null,
|
|
|
|
|
- gender: data.gender ?? "no_preference",
|
|
|
|
|
- degree: data.degree ?? null,
|
|
|
|
|
- email: data.email ?? null,
|
|
|
|
|
- phone: data.phone ?? null,
|
|
|
|
|
- postal_code: data.postal_code ?? null,
|
|
|
|
|
- street: data.street ?? null,
|
|
|
|
|
- address_number: data.address_number ?? null,
|
|
|
|
|
- neighborhood: data.neighborhood ?? null,
|
|
|
|
|
- state_id: data.state_id ?? null,
|
|
|
|
|
- city_id: data.city_id ?? null,
|
|
|
|
|
- complement: data.complement ?? null,
|
|
|
|
|
- notes: data.notes ?? null,
|
|
|
|
|
- };
|
|
|
|
|
|
|
+onMounted(loadResponsibles);
|
|
|
|
|
|
|
|
- if (data.state_id) {
|
|
|
|
|
- stateSelectRef.value?.selectStateById(data.state_id);
|
|
|
|
|
- }
|
|
|
|
|
- if (data.city_id) {
|
|
|
|
|
- citySelectRef.value?.selectCityById(data.city_id);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- console.error("Failed to load responsible:", error);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+function openDialog(responsible = null) {
|
|
|
|
|
+ $q.dialog({
|
|
|
|
|
+ component: ResponsibleDialog,
|
|
|
|
|
+ componentProps: { studentId: props.studentId, responsible },
|
|
|
|
|
+ }).onOk(loadResponsibles);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function buildPayload() {
|
|
|
|
|
- return {
|
|
|
|
|
- name: form.value.name,
|
|
|
|
|
- birth_date: form.value.birth_date
|
|
|
|
|
- ? formatDateDMYtoYMD(form.value.birth_date)
|
|
|
|
|
- : null,
|
|
|
|
|
- cpf: form.value.cpf,
|
|
|
|
|
- gender: form.value.gender,
|
|
|
|
|
- degree: form.value.degree,
|
|
|
|
|
- email: form.value.email,
|
|
|
|
|
- phone: form.value.phone,
|
|
|
|
|
- postal_code: form.value.postal_code,
|
|
|
|
|
- street: form.value.street,
|
|
|
|
|
- address_number: form.value.address_number,
|
|
|
|
|
- neighborhood: form.value.neighborhood,
|
|
|
|
|
- city_id: form.value.city_id,
|
|
|
|
|
- state_id: form.value.state_id,
|
|
|
|
|
- complement: form.value.complement,
|
|
|
|
|
- notes: form.value.notes,
|
|
|
|
|
- };
|
|
|
|
|
|
|
+function handleAdd() {
|
|
|
|
|
+ openDialog();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-onMounted(loadResponsible);
|
|
|
|
|
|
|
+function handleEdit(responsible) {
|
|
|
|
|
+ openDialog(responsible);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-defineExpose({
|
|
|
|
|
- validate: () => formRef.value?.validate(),
|
|
|
|
|
- buildPayload,
|
|
|
|
|
-});
|
|
|
|
|
|
|
+function handleDelete(responsible) {
|
|
|
|
|
+ $q.dialog({
|
|
|
|
|
+ title: "Excluir Responsável",
|
|
|
|
|
+ message: `Deseja excluir o responsável "${responsible.name}"?`,
|
|
|
|
|
+ cancel: true,
|
|
|
|
|
+ persistent: true,
|
|
|
|
|
+ }).onOk(async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await deleteStudentResponsible(responsible.id);
|
|
|
|
|
+ rows.value = rows.value.filter((r) => r.id !== responsible.id);
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error(e);
|
|
|
|
|
+ $q.notify({ type: "negative", message: "Erro ao excluir responsável." });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
</script>
|
|
</script>
|