1
0
mirror of https://github.com/PanJiaChen/vue-element-admin.git synced 2025-08-10 20:39:48 +08:00

feat: Add load dynamic form with fileName. (#450)

* feat: Add load dynamic form with fileName.

* Load Form metadata from server.
This commit is contained in:
Edwin Betancourt 2020-04-18 16:43:07 -04:00 committed by GitHub
parent 7fd5c8f334
commit 20a3bc3025
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 539 additions and 9 deletions

View File

@ -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",

View File

@ -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,

View File

@ -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>

View File

@ -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
})
}
}
}
}

View File

@ -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>

View File

@ -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

View File

@ -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;
}

View File

@ -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'

View File

@ -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 = {

View File

@ -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>