Form.vue 5.5 KB

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