StudentDataTab.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <template>
  2. <DefaultForm ref="formRef" @submit="onSave">
  3. <div class="flex justify-center q-mb-md">
  4. <AvatarImageComponent ref="avatarRef" @update:file="onAvatarChange" />
  5. </div>
  6. <div class="row q-col-gutter-sm">
  7. <DefaultInput
  8. v-model="form.name"
  9. :error="!!validationErrors.name"
  10. :error-message="validationErrors.name"
  11. label="Nome do Aluno"
  12. class="col-6"
  13. :rules="[inputRules.required]"
  14. />
  15. <DefaultInputDatePicker
  16. v-model="form.birthdate"
  17. :error="!!validationErrors.birth_date"
  18. :error-message="validationErrors.birth_date"
  19. label="Data de Nascimento"
  20. class="col-6"
  21. />
  22. <DefaultInput
  23. v-model="form.cpf"
  24. :error="!!validationErrors.document_number"
  25. :error-message="validationErrors.document_number"
  26. label="CPF"
  27. class="col-6"
  28. :mask="masks.Brasil.cpf"
  29. :rules="[inputRules.cpf]"
  30. />
  31. <DefaultSelect
  32. v-model="form.gender"
  33. :error="!!validationErrors.gender"
  34. :error-message="validationErrors.gender"
  35. label="Gênero"
  36. class="col-6"
  37. emit-value
  38. map-options
  39. :options="genderOptions"
  40. />
  41. <DefaultInput
  42. v-model="form.email"
  43. :error="!!validationErrors.email"
  44. :error-message="validationErrors.email"
  45. label="E-mail"
  46. class="col-6"
  47. type="email"
  48. />
  49. <DefaultInput
  50. v-model="form.phone"
  51. :error="!!validationErrors.phone"
  52. :error-message="validationErrors.phone"
  53. label="Celular com DDD"
  54. class="col-6"
  55. :mask="masks.Brasil.celular"
  56. />
  57. <DefaultCepInput
  58. v-model="form.cep"
  59. :error="!!validationErrors.postal_code"
  60. :error-message="validationErrors.postal_code"
  61. class="col-4"
  62. @rua="(v) => (form.address = v)"
  63. @bairro="(v) => (form.neighborhood = v)"
  64. @uf="(v) => stateSelectRef?.selectStateByCode(v)"
  65. @cidade="(v) => citySelectRef?.selectCityByName(v)"
  66. />
  67. <DefaultInput
  68. v-model="form.address"
  69. :error="!!validationErrors.street"
  70. :error-message="validationErrors.street"
  71. label="Endereço"
  72. class="col-5"
  73. />
  74. <DefaultInput
  75. v-model="form.address_number"
  76. :error="!!validationErrors.address_number"
  77. :error-message="validationErrors.address_number"
  78. label="Número"
  79. class="col-3"
  80. />
  81. <DefaultInput
  82. v-model="form.neighborhood"
  83. :error="!!validationErrors.neighborhood"
  84. :error-message="validationErrors.neighborhood"
  85. label="Bairro"
  86. class="col-4"
  87. />
  88. <CitySelect
  89. ref="citySelectRef"
  90. v-model="selectedCity"
  91. :error="!!validationErrors.city_id"
  92. :error-message="validationErrors.city_id"
  93. label="Cidade"
  94. class="col-4"
  95. :state="selectedState"
  96. :initial-id="props.student.city_id"
  97. />
  98. <StateSelect
  99. ref="stateSelectRef"
  100. v-model="selectedState"
  101. :error="!!validationErrors.state_id"
  102. :error-message="validationErrors.state_id"
  103. label="Estado"
  104. class="col-4"
  105. :initial-id="props.student.state_id"
  106. />
  107. <DefaultInput
  108. v-model="form.complement"
  109. :error="!!validationErrors.complement"
  110. :error-message="validationErrors.complement"
  111. label="Complemento"
  112. class="col-6"
  113. />
  114. <DefaultInput
  115. v-model="form.payer"
  116. :error="!!validationErrors.payer_name"
  117. :error-message="validationErrors.payer_name"
  118. label="Pagador"
  119. class="col-6"
  120. />
  121. <DefaultSelect
  122. v-model="form.how_found"
  123. :error="!!validationErrors.how_did_you_know_us"
  124. :error-message="validationErrors.how_did_you_know_us"
  125. label="Como nos conheceu?"
  126. class="col-12"
  127. emit-value
  128. map-options
  129. :options="howFoundOptions"
  130. />
  131. <DefaultInput
  132. v-model="form.notes"
  133. :error="!!validationErrors.notes"
  134. :error-message="validationErrors.notes"
  135. label="Observações"
  136. class="col-12"
  137. type="textarea"
  138. :input-style="{ minHeight: '120px' }"
  139. autogrow
  140. />
  141. </div>
  142. </DefaultForm>
  143. </template>
  144. <script setup>
  145. import { ref, watch, onMounted, useTemplateRef } from "vue";
  146. import DefaultInput from "src/components/defaults/DefaultInput.vue";
  147. import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
  148. import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
  149. import DefaultCepInput from "src/components/defaults/DefaultCepInput.vue";
  150. import AvatarImageComponent from "src/components/shared/AvatarImageComponent.vue";
  151. import StateSelect from "src/components/selects/StateSelect.vue";
  152. import CitySelect from "src/components/selects/CitySelect.vue";
  153. import { useInputRules } from "src/composables/useInputRules";
  154. import masks from "src/helpers/masks";
  155. import { formatDateYMDtoDMY, formatDateDMYtoYMD } from "src/helpers/utils";
  156. const props = defineProps({
  157. student: {
  158. type: Object,
  159. required: true,
  160. },
  161. validationErrors: {
  162. type: Object,
  163. default: () => ({}),
  164. },
  165. });
  166. const { inputRules } = useInputRules();
  167. const formRef = useTemplateRef("formRef");
  168. const avatarRef = useTemplateRef("avatarRef");
  169. const stateSelectRef = useTemplateRef("stateSelectRef");
  170. const citySelectRef = useTemplateRef("citySelectRef");
  171. const avatarFile = ref(null);
  172. const selectedState = ref(null);
  173. const selectedCity = ref(null);
  174. const genderOptions = [
  175. { label: "Prefiro não informar", value: "no_preference" },
  176. { label: "Masculino", value: "male" },
  177. { label: "Feminino", value: "female" },
  178. { label: "Outro", value: "other" },
  179. ];
  180. const howFoundOptions = [
  181. { label: "Indicação", value: "referral" },
  182. { label: "Redes Sociais", value: "social_media" },
  183. { label: "Google", value: "google" },
  184. { label: "Outro", value: "other" },
  185. ];
  186. const form = ref({
  187. name: props.student.name ?? null,
  188. birthdate: props.student.birth_date
  189. ? formatDateYMDtoDMY(props.student.birth_date)
  190. : null,
  191. cpf: props.student.document_number ?? null,
  192. gender: props.student.gender ?? "no_preference",
  193. email: props.student.email ?? null,
  194. phone: props.student.phone ?? null,
  195. cep: props.student.postal_code ?? null,
  196. address: props.student.street ?? null,
  197. address_number: props.student.address_number ?? null,
  198. neighborhood: props.student.neighborhood ?? null,
  199. state_id: props.student.state_id ?? null,
  200. city_id: props.student.city_id ?? null,
  201. complement: props.student.complement ?? null,
  202. payer: props.student.payer_name ?? null,
  203. how_found: props.student.how_did_you_know_us ?? null,
  204. notes: props.student.notes ?? null,
  205. });
  206. watch(selectedState, (state) => {
  207. form.value.state_id = state?.value ?? null;
  208. });
  209. watch(selectedCity, (city) => {
  210. form.value.city_id = city?.value ?? null;
  211. });
  212. onMounted(() => {
  213. if (props.student.photo_url) {
  214. avatarRef.value?.setImageUrl(props.student.photo_url);
  215. }
  216. });
  217. function onAvatarChange(file) {
  218. avatarFile.value = file;
  219. }
  220. function buildPayload() {
  221. if (avatarFile.value) {
  222. const formData = new FormData();
  223. formData.append("name", form.value.name ?? "");
  224. if (form.value.birthdate) {
  225. formData.append("birth_date", formatDateDMYtoYMD(form.value.birthdate));
  226. }
  227. formData.append("document_number", form.value.cpf ?? "");
  228. formData.append("gender", form.value.gender ?? "");
  229. formData.append("email", form.value.email ?? "");
  230. formData.append("phone", form.value.phone ?? "");
  231. formData.append("postal_code", form.value.cep ?? "");
  232. formData.append("street", form.value.address ?? "");
  233. formData.append("address_number", form.value.address_number ?? "");
  234. formData.append("neighborhood", form.value.neighborhood ?? "");
  235. if (form.value.state_id) {
  236. formData.append("state_id", form.value.state_id);
  237. }
  238. if (form.value.city_id) {
  239. formData.append("city_id", form.value.city_id);
  240. }
  241. formData.append("complement", form.value.complement ?? "");
  242. formData.append("payer_name", form.value.payer ?? "");
  243. formData.append("how_did_you_know_us", form.value.how_found ?? "");
  244. formData.append("notes", form.value.notes ?? "");
  245. formData.append("avatar", avatarFile.value);
  246. return formData;
  247. }
  248. return {
  249. name: form.value.name,
  250. birth_date: form.value.birthdate
  251. ? formatDateDMYtoYMD(form.value.birthdate)
  252. : null,
  253. document_number: form.value.cpf,
  254. gender: form.value.gender,
  255. email: form.value.email || null,
  256. phone: form.value.phone,
  257. postal_code: form.value.cep,
  258. street: form.value.address,
  259. address_number: form.value.address_number,
  260. neighborhood: form.value.neighborhood,
  261. state_id: form.value.state_id,
  262. city_id: form.value.city_id,
  263. complement: form.value.complement,
  264. payer_name: form.value.payer,
  265. how_did_you_know_us: form.value.how_found,
  266. notes: form.value.notes,
  267. };
  268. }
  269. defineExpose({
  270. validate: () => formRef.value?.validate(),
  271. buildPayload,
  272. });
  273. </script>