Form.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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 {markFormAsDirty, markFormAsNotDirty, readonly} = $useForm()
  102. const nextStepFactory = new UseNextStepFactory()
  103. const {id, query}: ToRefs = toRefs(props)
  104. const page = new Page(store)
  105. const form:Ref<any> = ref(null)
  106. const entry: ComputedRef<AnyJson> = computed(() => {
  107. return queryHelper.getFlattenEntry(query.value, id.value)
  108. })
  109. const updateRepository = (newValue: string, field: string) => {
  110. markFormAsDirty()
  111. repositoryHelper.updateStoreFromField(props.model, entry.value, newValue, field)
  112. }
  113. const submit = async (next: string|null = null) => {
  114. if(form.value.validate()){
  115. markFormAsNotDirty()
  116. try {
  117. const response = await $dataPersister.invoke({
  118. type: QUERY_TYPE.MODEL,
  119. model: props.model,
  120. id: store.state.form.formStatus === FORM_STATUS.EDIT ? id.value : null,
  121. idTemp: store.state.form.formStatus === FORM_STATUS.CREATE ? id.value : null,
  122. query: props.query
  123. })
  124. page.addAlerts(TYPE_ALERT.SUCCESS, [i18n.t('saveSuccess') as string])
  125. nextStep(next, response.data)
  126. } catch (error) {
  127. if (error.response.status === 422) {
  128. if(error.response.data['violations']){
  129. const violations:Array<string> = []
  130. const fields:Array<string> = []
  131. for(const violation of error.response.data['violations']){
  132. violations.push(i18n.t(violation['message']) as string)
  133. fields.push(violation['propertyPath'])
  134. }
  135. new Form(store).addViolations(fields)
  136. page.addAlerts(TYPE_ALERT.ALERT, violations)
  137. }
  138. }
  139. }
  140. }else{
  141. page.addAlerts(TYPE_ALERT.ALERT, [i18n.t('invalide_form') as string])
  142. }
  143. }
  144. const nextStep = (next: string|null, response: AnyJson) =>{
  145. if(next === null) return
  146. nextStepFactory.invoke(props.submitActions[next], response)[next]()
  147. }
  148. const showDialog: ComputedRef<boolean> = computed(() => {
  149. return store.state.form.showConfirmToLeave
  150. })
  151. const closeDialog = () => {
  152. store.commit('form/setShowConfirmToLeave', false)
  153. }
  154. const saveAndQuit = async () => {
  155. await submit()
  156. quitForm()
  157. }
  158. const quitForm = () => {
  159. markFormAsNotDirty()
  160. store.commit('form/setShowConfirmToLeave', false)
  161. const entryCopy = query.value.first()
  162. if (entryCopy && entryCopy.$getAttributes().originalState) {
  163. repositoryHelper.persist(props.model, entryCopy.$getAttributes().originalState)
  164. }
  165. if (router) {
  166. router.push(store.state.form.goAfterLeave)
  167. }
  168. }
  169. const actions = computed(()=>{
  170. return _.keys(props.submitActions)
  171. })
  172. return {
  173. form,
  174. submit,
  175. updateRepository,
  176. readonly,
  177. showDialog,
  178. entry,
  179. quitForm,
  180. closeDialog,
  181. saveAndQuit,
  182. actions
  183. }
  184. }
  185. })
  186. </script>
  187. <style scoped>
  188. .btnActions {
  189. text-align: right;
  190. }
  191. </style>