feat: Add load dynamic form with fileName. (#450)
* feat: Add load dynamic form with fileName. * Load Form metadata from server.pull/3759/head
							parent
							
								
									7fd5c8f334
								
							
						
					
					
						commit
						20a3bc3025
					
				|  | @ -47,7 +47,7 @@ | |||
|     "@adempiere/grpc-access-client": "^1.1.8", | ||||
|     "@adempiere/grpc-data-client": "^2.2.1", | ||||
|     "@adempiere/grpc-pos-client": "^1.0.3", | ||||
|     "@adempiere/grpc-dictionary-client": "^1.3.8", | ||||
|     "@adempiere/grpc-dictionary-client": "^1.3.9", | ||||
|     "@adempiere/grpc-enrollment-client": "^1.0.7", | ||||
|     "autoprefixer": "^9.5.1", | ||||
|     "axios": "0.18.0", | ||||
|  |  | |||
|  | @ -65,6 +65,18 @@ export function getField({ | |||
|   }) | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Request Form | ||||
|  * @param {string} uuid | ||||
|  * @param {number} id, integer identifier | ||||
|  */ | ||||
| export function requestForm({ uuid, id }) { | ||||
|   return Instance.call(this).requestForm({ | ||||
|     uuid, | ||||
|     id | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| export function requestReference({ referenceUuid, columnName }) { | ||||
|   return Instance.call(this).requestReference({ | ||||
|     referenceUuid, | ||||
|  |  | |||
|  | @ -0,0 +1,137 @@ | |||
| <template> | ||||
|   <div class="wrapper"> | ||||
|     <el-form | ||||
|       v-if="isLoaded" | ||||
|       key="form-loaded" | ||||
|       label-position="top" | ||||
|       label-width="200px" | ||||
|     > | ||||
|       <el-row> | ||||
|         <field | ||||
|           v-for="(metadata) in metadataList" | ||||
|           :key="metadata.columnName" | ||||
|           :metadata-field="metadata" | ||||
|         /> | ||||
|       </el-row> | ||||
|     </el-form> | ||||
|     <div | ||||
|       v-else | ||||
|       key="form-loading" | ||||
|       v-loading="!isLoaded" | ||||
|       :element-loading-text="$t('notifications.loading')" | ||||
|       element-loading-spinner="el-icon-loading" | ||||
|       element-loading-background="rgba(255, 255, 255, 0.8)" | ||||
|       class="loading-panel" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import formMixin from '@/components/ADempiere/Form/formMixin' | ||||
| import { COSTS_PLUS_PRICES, CHAR, TEXT } from '@/utils/ADempiere/references' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'TestView', | ||||
|   mixins: [formMixin], | ||||
|   data() { | ||||
|     return { | ||||
|       metadataList: [], | ||||
|       panelMetadata: {}, | ||||
|       isLoaded: false, | ||||
|       panelType: 'custom' | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     getterPanel() { | ||||
|       return this.$store.getters.getPanel(this.metadata.containerUuid) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getPanel() | ||||
|   }, | ||||
|   methods: { | ||||
|     setFieldsList() { | ||||
|       const fieldsList = [] | ||||
|       let sequence = 10 | ||||
|       const sequenceIncrement = () => { | ||||
|         sequence = sequence + 10 | ||||
|         return sequence | ||||
|       } | ||||
| 
 | ||||
|       fieldsList.push(this.createField({ | ||||
|         containerUuid: this.metadata.containerUuid, | ||||
|         columnName: 'Value', | ||||
|         definition: { | ||||
|           name: 'Product Code/Bar Code', | ||||
|           displayType: CHAR.id, | ||||
|           panelType: this.panelType, | ||||
|           sequence, | ||||
|           size: 24 | ||||
|         } | ||||
|       })) | ||||
| 
 | ||||
|       fieldsList.push(this.createField({ | ||||
|         containerUuid: this.metadata.containerUuid, | ||||
|         columnName: 'Name', | ||||
|         definition: { | ||||
|           name: 'Product Name', | ||||
|           displayType: TEXT.id, | ||||
|           panelType: this.panelType, | ||||
|           sequence: sequenceIncrement(), | ||||
|           size: 24 | ||||
|         } | ||||
|       })) | ||||
| 
 | ||||
|       fieldsList.push(this.createField({ | ||||
|         containerUuid: this.metadata.containerUuid, | ||||
|         columnName: 'Description', | ||||
|         definition: { | ||||
|           name: 'Product Description', | ||||
|           displayType: TEXT.id, | ||||
|           panelType: this.panelType, | ||||
|           sequence: sequenceIncrement(), | ||||
|           size: 24 | ||||
|         } | ||||
|       })) | ||||
| 
 | ||||
|       fieldsList.push(this.createField({ | ||||
|         containerUuid: this.metadata.containerUuid, | ||||
|         columnName: 'Price', | ||||
|         definition: { | ||||
|           name: 'Price', | ||||
|           displayType: COSTS_PLUS_PRICES.id, | ||||
|           panelType: this.panelType, | ||||
|           sequence: sequenceIncrement(), | ||||
|           size: 16 | ||||
|         } | ||||
|       })) | ||||
| 
 | ||||
|       fieldsList.push(this.createField({ | ||||
|         containerUuid: this.metadata.containerUuid, | ||||
|         columnName: 'Tax', | ||||
|         definition: { | ||||
|           name: 'Tax', | ||||
|           displayType: COSTS_PLUS_PRICES.id, | ||||
|           panelType: this.panelType, | ||||
|           sequence: sequenceIncrement(), | ||||
|           size: 8 | ||||
|         } | ||||
|       })) | ||||
| 
 | ||||
|       fieldsList.push(this.createField({ | ||||
|         containerUuid: this.metadata.containerUuid, | ||||
|         columnName: 'Total', | ||||
|         definition: { | ||||
|           name: 'Total', | ||||
|           displayType: COSTS_PLUS_PRICES.id, | ||||
|           panelType: this.panelType, | ||||
|           sequence: sequenceIncrement(), | ||||
|           size: 24 | ||||
|         } | ||||
|       })) | ||||
| 
 | ||||
|       this.metadataList = fieldsList | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | @ -0,0 +1,59 @@ | |||
| import Field from '@/components/ADempiere/Field' | ||||
| import { createField, createFieldDictionary } from '@/utils/ADempiere/lookupFactory' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'FormMixn', | ||||
|   components: { | ||||
|     Field | ||||
|   }, | ||||
|   props: { | ||||
|     metadata: { | ||||
|       type: Object, | ||||
|       required: true | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       metadataList: [], | ||||
|       panelMetadata: {}, | ||||
|       isLoaded: false, | ||||
|       panelType: 'custom' | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     getterPanel() { | ||||
|       return this.$store.getters.getPanel(this.metadata.containerUuid) | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     createField, | ||||
|     createFieldDictionary, | ||||
|     getPanel() { | ||||
|       const panel = this.getterPanel | ||||
|       if (panel) { | ||||
|         this.metadataList = panel.fieldList | ||||
|         this.isLoaded = true | ||||
|       } else { | ||||
|         this.setFieldsList() | ||||
|         this.$store.dispatch('addPanel', { | ||||
|           ...this.metadata, | ||||
|           uuid: this.metadata.containerUuid, | ||||
|           panelType: this.panelType, | ||||
|           fieldList: this.metadataList | ||||
|         }) | ||||
|           .then(responsePanel => { | ||||
|             this.metadataList = responsePanel.fieldList | ||||
| 
 | ||||
|             this.$store.dispatch('changeFormAttribute', { | ||||
|               containerUuid: this.metadata.containerUuid, | ||||
|               attributeName: 'fieldList', | ||||
|               attributeValue: this.metadataList | ||||
|             }) | ||||
|           }) | ||||
|           .finally(() => { | ||||
|             this.isLoaded = true | ||||
|           }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,37 @@ | |||
| <template> | ||||
|   <component | ||||
|     :is="componentRender" | ||||
|     :metadata="metadata" | ||||
|   /> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| export default { | ||||
|   name: 'FormPanel', | ||||
|   props: { | ||||
|     metadata: { | ||||
|       type: Object, | ||||
|       required: true | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     // load the component that is indicated in the attributes of received property | ||||
|     componentRender() { | ||||
|       return () => { | ||||
|         return new Promise(resolve => { | ||||
|           import(`@/components/ADempiere/Form/${this.metadata.fileName}`) | ||||
|             .then(formFile => { | ||||
|               resolve(formFile) | ||||
|             }) | ||||
|             .catch(() => { | ||||
|               import('@/views/ADempiere/Unsupported') | ||||
|                 .then(unsupportedFile => { | ||||
|                   resolve(unsupportedFile) | ||||
|                 }) | ||||
|             }) | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | @ -0,0 +1,100 @@ | |||
| import { requestForm } from '@/api/ADempiere/dictionary' | ||||
| import { showMessage } from '@/utils/ADempiere/notification' | ||||
| import { isEmptyValue } from '@/utils/ADempiere/valueUtils' | ||||
| import router from '@/router' | ||||
| import language from '@/lang' | ||||
| 
 | ||||
| const form = { | ||||
|   state: { | ||||
|     form: [] | ||||
|   }, | ||||
|   mutations: { | ||||
|     addForm(state, payload) { | ||||
|       state.form.push(payload) | ||||
|     }, | ||||
|     dictionaryResetCacheForm(state) { | ||||
|       state.form = [] | ||||
|     }, | ||||
|     changeFormAttribute(state, payload) { | ||||
|       let value = payload.attributeValue | ||||
|       if (payload.attributeNameControl) { | ||||
|         value = payload.form[payload.attributeNameControl] | ||||
|       } | ||||
|       payload.form[payload.attributeName] = value | ||||
|     } | ||||
|   }, | ||||
|   actions: { | ||||
|     getFormFromServer({ commit, dispatch }, { | ||||
|       id, | ||||
|       containerUuid, | ||||
|       routeToDelete | ||||
|     }) { | ||||
|       return new Promise(resolve => { | ||||
|         requestForm({ | ||||
|           uuid: containerUuid, | ||||
|           id | ||||
|         }) | ||||
|           .then(formResponse => { | ||||
|             const panelType = 'form' | ||||
| 
 | ||||
|             // Panel for save on store
 | ||||
|             const newForm = { | ||||
|               ...formResponse, | ||||
|               containerUuid, | ||||
|               fieldList: [], | ||||
|               panelType | ||||
|             } | ||||
| 
 | ||||
|             commit('addForm', newForm) | ||||
|             // dispatch('addPanel', newForm)
 | ||||
| 
 | ||||
|             resolve(newForm) | ||||
| 
 | ||||
|             // Convert from gRPC process list
 | ||||
|             const actions = [] | ||||
| 
 | ||||
|             // Add process menu
 | ||||
|             dispatch('setContextMenu', { | ||||
|               containerUuid, | ||||
|               actions | ||||
|             }) | ||||
|           }) | ||||
|           .catch(error => { | ||||
|             router.push({ path: '/dashboard' }) | ||||
|             dispatch('tagsView/delView', routeToDelete) | ||||
|             showMessage({ | ||||
|               message: language.t('login.unexpectedError'), | ||||
|               type: 'error' | ||||
|             }) | ||||
|             console.warn(`Dictionary form - Error ${error.code}: ${error.message}.`) | ||||
|           }) | ||||
|       }) | ||||
|     }, | ||||
|     changeFormAttribute({ commit, getters }, { | ||||
|       containerUuid, | ||||
|       form, | ||||
|       attributeName, | ||||
|       attributeNameControl, | ||||
|       attributeValue | ||||
|     }) { | ||||
|       if (isEmptyValue(form)) { | ||||
|         form = getters.getForm(containerUuid) | ||||
|       } | ||||
|       commit('changeFormAttribute', { | ||||
|         form, | ||||
|         attributeName, | ||||
|         attributeValue, | ||||
|         attributeNameControl | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   getters: { | ||||
|     getForm: (state) => (formUuid) => { | ||||
|       return state.form.find( | ||||
|         item => item.uuid === formUuid | ||||
|       ) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export default form | ||||
|  | @ -0,0 +1,17 @@ | |||
| 
 | ||||
| .view-base { | ||||
|   height: 100%; | ||||
|   min-height: calc(100vh - 84px); | ||||
| } | ||||
| 
 | ||||
| .view-loading { | ||||
|   padding: 100px 100px; | ||||
|   height: 100%; | ||||
| } | ||||
| 
 | ||||
| .custom-title { | ||||
|   color: #000000; | ||||
|   text-size-adjust: 20px; | ||||
|   font-size: 100%; | ||||
|   font-weight: 605!important; | ||||
| } | ||||
|  | @ -553,6 +553,7 @@ export function convertAction(action) { | |||
|     case 'X': | ||||
|       actionAttributes.name = 'form' | ||||
|       actionAttributes.icon = 'form' | ||||
|       actionAttributes.component = () => import('@/views/ADempiere/Form') | ||||
|       break | ||||
|     default: | ||||
|       actionAttributes.name = 'summary' | ||||
|  |  | |||
|  | @ -93,7 +93,7 @@ export function createFieldDictionary({ | |||
|     }) | ||||
|       .then(response => { | ||||
|         resolve(getFactoryFromField({ | ||||
|           containerUuid: containerUuid, | ||||
|           containerUuid, | ||||
|           field: response | ||||
|         })) | ||||
|       }).catch(error => { | ||||
|  | @ -242,14 +242,32 @@ export function getFieldTemplate(attributesOverwrite) { | |||
|   const componentReference = evalutateTypeField(displayType) | ||||
|   const referenceType = componentReference.alias[0] | ||||
| 
 | ||||
|   let sizeFieldFromType = FIELDS_DISPLAY_SIZES.find(item => { | ||||
|     return item.type === componentReference.type | ||||
|   }) | ||||
|   if (isEmptyValue(sizeFieldFromType)) { | ||||
|     sizeFieldFromType = { | ||||
|       type: referenceType, | ||||
|       size: DEFAULT_SIZE.size | ||||
|   // set size from displayed, max 24
 | ||||
|   let size = DEFAULT_SIZE.size | ||||
|   if (!isEmptyValue(attributesOverwrite.size)) { | ||||
|     size = attributesOverwrite.size | ||||
|     delete attributesOverwrite.size | ||||
|     if (typeof size === 'number') { | ||||
|       size = { | ||||
|         xs: size, | ||||
|         sm: size, | ||||
|         md: size, | ||||
|         lg: size, | ||||
|         xl: size | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     const sizeComponent = FIELDS_DISPLAY_SIZES.find(item => { | ||||
|       return item.type === componentReference.type | ||||
|     }) | ||||
|     if (!isEmptyValue(sizeComponent)) { | ||||
|       size = sizeComponent.size | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   const sizeFieldFromType = { | ||||
|     type: referenceType, | ||||
|     size | ||||
|   } | ||||
| 
 | ||||
|   const fieldTemplateMetadata = { | ||||
|  |  | |||
|  | @ -0,0 +1,149 @@ | |||
| <template> | ||||
|   <el-container | ||||
|     v-if="isLoaded" | ||||
|     key="form-loaded" | ||||
|     class="view-base" | ||||
|     style="height: 84vh;" | ||||
|   > | ||||
|     <el-popover | ||||
|       v-if="!isEmptyValue(formMetadata.help)" | ||||
|       ref="helpTitle" | ||||
|       placement="top-start" | ||||
|       :title="formTitle" | ||||
|       width="400" | ||||
|       trigger="hover" | ||||
|     > | ||||
|       <div v-html="formMetadata.help" /> | ||||
|     </el-popover> | ||||
|     <div class="w-33"> | ||||
|       <div class="center"> | ||||
|         <el-button | ||||
|           v-popover:helpTitle | ||||
|           type="text" | ||||
|           class="title text-center" | ||||
|         > | ||||
|           {{ formTitle }} | ||||
|         </el-button> | ||||
|       </div> | ||||
|     </div> | ||||
|     <form-panel | ||||
|       :metadata="{ | ||||
|         ...formMetadata, | ||||
|         containerUuid: formUuid, | ||||
|         title: formTitle | ||||
|       }" | ||||
|     /> | ||||
|   </el-container> | ||||
|   <div | ||||
|     v-else | ||||
|     key="form-loading" | ||||
|     v-loading="!isLoaded" | ||||
|     :element-loading-text="$t('notifications.loading')" | ||||
|     element-loading-spinner="el-icon-loading" | ||||
|     element-loading-background="rgba(255, 255, 255, 0.8)" | ||||
|     class="view-loading" | ||||
|   /> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import FormPanel from '@/components/ADempiere/Form' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'FormView', | ||||
|   components: { | ||||
|     FormPanel | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       formUuid: this.$route.meta.uuid, | ||||
|       formMetadata: {}, | ||||
|       isLoaded: false | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     formTitle() { | ||||
|       return this.formMetadata.name || this.$route.meta.title | ||||
|     }, | ||||
|     getterForm() { | ||||
|       return this.$store.getters.getForm(this.formUuid) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getForm() | ||||
|   }, | ||||
|   methods: { | ||||
|     getForm() { | ||||
|       const panel = this.getterForm | ||||
|       if (panel) { | ||||
|         this.formMetadata = panel | ||||
|         this.isLoaded = true | ||||
|       } else { | ||||
|         this.$store.dispatch('getFormFromServer', { | ||||
|           containerUuid: this.formUuid, | ||||
|           routeToDelete: this.$rote | ||||
|         }) | ||||
|           .then(responseForm => { | ||||
|             this.formMetadata = responseForm | ||||
|           }) | ||||
|           .finally(() => { | ||||
|             this.isLoaded = true | ||||
|           }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   .view-base { | ||||
|     height: 100%; | ||||
|     min-height: calc(100vh - 84px); | ||||
|   } | ||||
| 
 | ||||
|   .view-loading { | ||||
|     padding: 100px 100px; | ||||
|     height: 100%; | ||||
|   } | ||||
| 
 | ||||
|   .custom-title { | ||||
|     color: #000000; | ||||
|     text-size-adjust: 20px; | ||||
|     font-size: 100%; | ||||
|     font-weight: 605 !important; | ||||
|   } | ||||
| 
 | ||||
|   .title { | ||||
|     color: #000000; | ||||
|     text-size-adjust: 20px; | ||||
|     font-size: 100%; | ||||
|     font-weight: 605!important; | ||||
|     /* left: 50%; */ | ||||
|   } | ||||
| 
 | ||||
|   .w-33 { | ||||
|     width: 100%; | ||||
|     background-color: transparent; | ||||
|   } | ||||
| 
 | ||||
|   .warn-content { | ||||
|     margin: 0px 0px !important; | ||||
|     padding-top: 0px !important; | ||||
|   } | ||||
|   .content-help { | ||||
|     width: 100%; | ||||
|     height: 200%; | ||||
|     padding-left: 39px !important; | ||||
|   } | ||||
|   .el-card { | ||||
|     width: 100% !important; | ||||
|     height: 200% !important; | ||||
|   } | ||||
|   .content-collapse { | ||||
|     padding-left: 20 px !important; | ||||
|     padding-top: 50 px !important; | ||||
|   } | ||||
| 
 | ||||
|   .center{ | ||||
|     text-align: center; | ||||
|   } | ||||
| </style> | ||||
		Loading…
	
		Reference in New Issue
	
	 Edwin Betancourt
						Edwin Betancourt