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:
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,
|
||||
|
137
src/components/ADempiere/Form/PriceInquiry/index.vue
Normal file
137
src/components/ADempiere/Form/PriceInquiry/index.vue
Normal 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>
|
59
src/components/ADempiere/Form/formMixin.js
Normal file
59
src/components/ADempiere/Form/formMixin.js
Normal 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
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
37
src/components/ADempiere/Form/index.vue
Normal file
37
src/components/ADempiere/Form/index.vue
Normal 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>
|
100
src/store/modules/ADempiere/form.js
Normal file
100
src/store/modules/ADempiere/form.js
Normal 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
|
17
src/styles/ADempiere/view.scss
Normal file
17
src/styles/ADempiere/view.scss
Normal 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;
|
||||
}
|
@ -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 = {
|
||||
|
149
src/views/ADempiere/Form/index.vue
Normal file
149
src/views/ADempiere/Form/index.vue
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user