Form.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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. v-model="properties.valid"
  10. lazy-validation
  11. :readonly="readOnly"
  12. >
  13. <v-container fluid class="container btnActions">
  14. <v-row>
  15. <v-col cols="12" sm="12">
  16. <slot name="form.button" />
  17. <v-btn v-if="!readOnly" class="mr-4 ot_green ot_white--text" @click="submit">
  18. {{ $t('save') }}
  19. </v-btn>
  20. </v-col>
  21. </v-row>
  22. </v-container>
  23. <slot name="form.input" v-bind="{entry,updateRepository}" />
  24. <v-container fluid class="container btnActions">
  25. <v-row>
  26. <v-col cols="12" sm="12">
  27. <slot name="form.button" />
  28. <v-btn v-if="!readOnly" class="mr-4 ot_green ot_white--text" @click="submit">
  29. {{ $t('save') }}
  30. </v-btn>
  31. </v-col>
  32. </v-row>
  33. </v-container>
  34. </v-form>
  35. <lazy-LayoutDialog
  36. :show="showDialog"
  37. >
  38. <template v-slot:dialogText>
  39. <v-card-title class="text-h5 grey lighten-2">
  40. {{ $t('attention') }}
  41. </v-card-title>
  42. <v-card-text>
  43. <br>
  44. <p>{{ $t('quit_without_saving_warning') }}</p>
  45. </v-card-text>
  46. </template>
  47. <template v-slot:dialogBtn>
  48. <v-btn class="mr-4 submitBtn ot_green ot_white--text" @click="closeDialog">
  49. {{ $t('back_to_form') }}
  50. </v-btn>
  51. <v-btn class="mr-4 submitBtn ot_green ot_white--text" @click="saveAndQuit">
  52. {{ $t('save_and_quit') }}
  53. </v-btn>
  54. <v-btn class="mr-4 submitBtn ot_danger ot_white--text" @click="goEvenUnsavedData">
  55. {{ $t('quit_form') }}
  56. </v-btn>
  57. </template>
  58. </lazy-LayoutDialog>
  59. </main>
  60. </template>
  61. <script lang="ts">
  62. import { computed, defineComponent, onBeforeMount, onBeforeUnmount, onUnmounted, reactive, toRefs, useContext, watch, ref, Ref, ComputedRef } from '@nuxtjs/composition-api'
  63. import { Query } from '@vuex-orm/core'
  64. import { ToRefs, UnwrapRef } from '@vue/composition-api'
  65. import { repositoryHelper } from '~/services/store/repository'
  66. import { queryHelper } from '~/services/store/query'
  67. import { QUERY_TYPE, TYPE_ALERT } from '~/types/enums'
  68. import { alert, AnyJson } from '~/types/interfaces'
  69. import { $useDirtyForm } from '~/use/form/useDirtyForm'
  70. export default defineComponent({
  71. props: {
  72. model: {
  73. type: Function,
  74. required: true
  75. },
  76. id: {
  77. type: Number,
  78. required: true
  79. },
  80. query: {
  81. type: Object as () => Query,
  82. required: true
  83. }
  84. },
  85. setup (props) {
  86. const { $dataPersister, store, app: { router, i18n } } = useContext()
  87. const { markFormAsDirty, markFormAsNotDirty } = $useDirtyForm(store)
  88. const { id, query }:ToRefs = toRefs(props)
  89. const properties:UnwrapRef<AnyJson> = reactive({
  90. valid: false,
  91. saveOk: false,
  92. saveKo: false
  93. })
  94. const readOnly:Ref<boolean> = ref(false)
  95. const entry:ComputedRef<AnyJson> = computed(() => {
  96. return queryHelper.getFlattenEntry(query.value, id.value)
  97. })
  98. const updateRepository = (newValue: string, field: string) => {
  99. markFormAsDirty()
  100. repositoryHelper.updateStoreFromField(props.model, entry.value, newValue, field)
  101. }
  102. const submit = async () => {
  103. try {
  104. markFormAsNotDirty()
  105. await $dataPersister.invoke({
  106. type: QUERY_TYPE.MODEL,
  107. model: props.model,
  108. id: id.value
  109. })
  110. const alert:alert = {
  111. type: TYPE_ALERT.SUCCESS,
  112. message: i18n.t('saveSuccess') as string
  113. }
  114. store.commit('page/setAlert', alert)
  115. } catch (error) {
  116. const alert:alert = {
  117. type: TYPE_ALERT.ALERT,
  118. message: error.message
  119. }
  120. store.commit('page/setAlert', alert)
  121. }
  122. }
  123. const showDialog:ComputedRef<boolean> = computed(() => {
  124. return store.state.form.showConfirmToLeave
  125. })
  126. const closeDialog = () => {
  127. store.commit('form/setShowConfirmToLeave', false)
  128. }
  129. const saveAndQuit = async () => {
  130. await submit()
  131. goEvenUnsavedData()
  132. }
  133. const goEvenUnsavedData = () => {
  134. markFormAsNotDirty()
  135. store.commit('form/setShowConfirmToLeave', false)
  136. const entryCopy = query.value.first()
  137. if (entryCopy && entryCopy.$getAttributes().originalState) {
  138. repositoryHelper.persist(props.model, entryCopy.$getAttributes().originalState)
  139. }
  140. if (router) {
  141. router.push(store.state.form.goAfterLeave)
  142. }
  143. }
  144. return {
  145. submit,
  146. updateRepository,
  147. properties,
  148. readOnly,
  149. showDialog,
  150. entry,
  151. goEvenUnsavedData,
  152. closeDialog,
  153. saveAndQuit
  154. }
  155. }
  156. })
  157. </script>
  158. <style scoped>
  159. .btnActions {
  160. text-align: right;
  161. }
  162. </style>