Form.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <!--
  2. Formulaire générique
  3. @see https://vuetifyjs.com/en/components/forms/#usage
  4. -->
  5. <template>
  6. <main>
  7. <v-form
  8. ref="form"
  9. lazy-validation
  10. :readonly="readonly"
  11. >
  12. <v-container fluid class="container btnActions">
  13. <v-row>
  14. <v-col cols="12" sm="12">
  15. <slot name="form.button"/>
  16. <UiButtonSubmit
  17. v-if="!readonly"
  18. @submit="submit"
  19. :actions="actions"
  20. ></UiButtonSubmit>
  21. </v-col>
  22. </v-row>
  23. </v-container>
  24. <slot name="form.input" v-bind="{entry,updateRepository}"/>
  25. <v-container fluid class="container btnActions">
  26. <v-row>
  27. <v-col cols="12" sm="12">
  28. <slot name="form.button"/>
  29. <UiButtonSubmit
  30. @submit="submit"
  31. :actions="actions"
  32. ></UiButtonSubmit>
  33. </v-col>
  34. </v-row>
  35. </v-container>
  36. </v-form>
  37. <lazy-LayoutDialog
  38. :show="showDialog"
  39. >
  40. <template #dialogText>
  41. <v-card-title class="text-h5 grey lighten-2">
  42. {{ $t('attention') }}
  43. </v-card-title>
  44. <v-card-text>
  45. <br>
  46. <p>{{ $t('quit_without_saving_warning') }}</p>
  47. </v-card-text>
  48. </template>
  49. <template #dialogBtn>
  50. <v-btn class="mr-4 submitBtn ot_green ot_white--text" @click="closeDialog">
  51. {{ $t('back_to_form') }}
  52. </v-btn>
  53. <v-btn class="mr-4 submitBtn ot_green ot_white--text" @click="saveAndQuit">
  54. {{ $t('save_and_quit') }}
  55. </v-btn>
  56. <v-btn class="mr-4 submitBtn ot_danger ot_white--text" @click="quitForm">
  57. {{ $t('quit_form') }}
  58. </v-btn>
  59. </template>
  60. </lazy-LayoutDialog>
  61. </main>
  62. </template>
  63. <script lang="ts">
  64. import {computed, ComputedRef, defineComponent, ref, Ref, toRefs, ToRefs, useContext} from '@nuxtjs/composition-api'
  65. import {Query} from '@vuex-orm/core'
  66. import {repositoryHelper} from '~/services/store/repository'
  67. import {queryHelper} from '~/services/store/query'
  68. import {FORM_STATUS, QUERY_TYPE, SUBMIT_TYPE, TYPE_ALERT} from '~/types/enums'
  69. import {AnyJson} from '~/types/interfaces'
  70. import {useForm} from "~/composables/form/useForm";
  71. import * as _ from 'lodash'
  72. import Form from "~/services/store/form";
  73. import Page from "~/services/store/page";
  74. import UseNextStepFactory from "~/composables/form/useNextStepFactory";
  75. export default defineComponent({
  76. props: {
  77. model: {
  78. type: Function,
  79. required: true
  80. },
  81. id: {
  82. type: [Number, String],
  83. required: true
  84. },
  85. query: {
  86. type: Object as () => Query,
  87. required: true
  88. },
  89. submitActions: {
  90. type: Object,
  91. required: false,
  92. default: () => {
  93. let actions:AnyJson = {}
  94. actions[SUBMIT_TYPE.SAVE] = {}
  95. return actions
  96. }
  97. }
  98. },
  99. setup(props) {
  100. const {$dataPersister, store, app: {router, i18n}} = useContext()
  101. const {markAsDirty, markAsNotDirty, readonly, nextStepFactory} = useForm(store)
  102. const {id, query}: ToRefs = toRefs(props)
  103. const page = new Page(store)
  104. const form:Ref<any> = ref(null)
  105. const entry: ComputedRef<AnyJson> = computed(() => {
  106. return queryHelper.getFlattenEntry(query.value, id.value)
  107. })
  108. const updateRepository = (newValue: string, field: string) => {
  109. markAsDirty()
  110. repositoryHelper.updateStoreFromField(props.model, entry.value, newValue, field)
  111. }
  112. const submit = async (next: string|null = null) => {
  113. if(form.value.validate()){
  114. markAsNotDirty()
  115. try {
  116. const response = await $dataPersister.invoke({
  117. type: QUERY_TYPE.MODEL,
  118. model: props.model,
  119. id: store.state.form.formStatus === FORM_STATUS.EDIT ? id.value : null,
  120. idTemp: store.state.form.formStatus === FORM_STATUS.CREATE ? id.value : null,
  121. query: props.query
  122. })
  123. page.addAlerts(TYPE_ALERT.SUCCESS, [i18n.t('saveSuccess') as string])
  124. nextStep(next, response.data)
  125. } catch (error) {
  126. if (error.response.status === 422) {
  127. if(error.response.data['violations']){
  128. const violations:Array<string> = []
  129. const fields:Array<string> = []
  130. for(const violation of error.response.data['violations']){
  131. violations.push(i18n.t(violation['message']) as string)
  132. fields.push(violation['propertyPath'])
  133. }
  134. new Form(store).addViolations(fields)
  135. page.addAlerts(TYPE_ALERT.ALERT, violations)
  136. }
  137. }
  138. }
  139. }else{
  140. page.addAlerts(TYPE_ALERT.ALERT, [i18n.t('invalide_form') as string])
  141. }
  142. }
  143. const nextStep = (next: string|null, response: AnyJson) =>{
  144. if(next === null) return
  145. nextStepFactory(props.submitActions[next], response, router)[next]()
  146. }
  147. const showDialog: ComputedRef<boolean> = computed(() => {
  148. return store.state.form.showConfirmToLeave
  149. })
  150. const closeDialog = () => {
  151. store.commit('form/setShowConfirmToLeave', false)
  152. }
  153. const saveAndQuit = async () => {
  154. await submit()
  155. quitForm()
  156. }
  157. const quitForm = () => {
  158. markAsNotDirty()
  159. store.commit('form/setShowConfirmToLeave', false)
  160. const entryCopy = query.value.first()
  161. if (entryCopy && entryCopy.$getAttributes().originalState) {
  162. repositoryHelper.persist(props.model, entryCopy.$getAttributes().originalState)
  163. }
  164. if (router) {
  165. router.push(store.state.form.goAfterLeave)
  166. }
  167. }
  168. const actions = computed(()=>{
  169. return _.keys(props.submitActions)
  170. })
  171. return {
  172. form,
  173. submit,
  174. updateRepository,
  175. readonly,
  176. showDialog,
  177. entry,
  178. quitForm,
  179. closeDialog,
  180. saveAndQuit,
  181. actions
  182. }
  183. }
  184. })
  185. </script>
  186. <style scoped>
  187. .btnActions {
  188. text-align: right;
  189. }
  190. </style>