<template>
  <div :style="{width: formData.config && formData.config.width}" class="fm-form"
    :class="{
      ['fm-'+formStyleKey]: true,
      'is-print': printRead
    }"
  >
    <el-form :ref="formRef"
      :key="formKey"
      v-if="formShow"
      :class="{
        [formData.config && formData.config.customClass]:  (formData.config && formData.config.customClass) ? true : false,
        'no-label-form': formData.config && (formData.config.labelWidth == 0)
      }"
      :size="formSize"
      :model="models"
      :rules="rules"
      :label-position="formData.config && formData.config.labelPosition"
      :disabled="!edit"
      :label-width="formData.config && formData.config.labelWidth + 'px'"
      :label-suffix="formData.config?.labelSuffix ? ' : ' : ' '"
    >

      <template v-for="item in formData.list">
        <generate-col-item
          v-if="item.type == 'grid'"
          :key="item.key"
          :model="models"
          :rules="rules"
          :element="item"
          :remote="remote"
          :blanks="blanks"
          :display="displayFields"
          @input-change="onInputChange"
          :edit="edit"
          :remote-option="remoteOption"
          :platform="platform"
          :preview="preview"
          :container-key="containerKey"
          :data-source-value="dataSourceValue"
          :event-function="eventFunction"
          :print-read="printRead"
          :form-component="$refs[formRef]"
          :group="''"
          :field-node="''"
        >
          <template v-slot:[blank.name]="scope" v-for="blank in blanks">
            <slot :name="blank.name" :model="scope.model"></slot>
          </template>
        </generate-col-item>

        <generate-tab-item
          v-else-if="item.type == 'tabs'"
          :key="item.key"
          :model="models"
          :rules="rules"
          :element="item"
          :remote="remote"
          :blanks="blanks"
          :display="displayFields"
          @input-change="onInputChange"
          :edit="edit"
          :remote-option="remoteOption"
          :platform="platform"
          :preview="preview"
          :container-key="containerKey"
          :data-source-value="dataSourceValue"
          :event-function="eventFunction"
          :print-read="printRead"
          :form-component="$refs[formRef]"
          :group="''"
          :field-node="''"
        >
          <template v-slot:[blank.name]="scope" v-for="blank in blanks">
            <slot :name="blank.name" :model="scope.model"></slot>
          </template>
        </generate-tab-item>

        <generate-collapse
          v-else-if="item.type == 'collapse'"
          :key="item.key"
          :model="models"
          :rules="rules"
          :element="item"
          :remote="remote"
          :blanks="blanks"
          :display="displayFields"
          @input-change="onInputChange"
          :edit="edit"
          :remote-option="remoteOption"
          :platform="platform"
          :preview="preview"
          :container-key="containerKey"
          :data-source-value="dataSourceValue"
          :event-function="eventFunction"
          :print-read="printRead"
          :form-component="$refs[formRef]"
          :group="''"
          :field-node="''"
        >
          <template v-slot:[blank.name]="scope" v-for="blank in blanks">
            <slot :name="blank.name" :model="scope.model"></slot>
          </template>
        </generate-collapse>

        <generate-report
          v-else-if="item.type == 'report'"
          :key="item.key"
          :model="models"
          :rules="rules"
          :element="item"
          :remote="remote"
          :blanks="blanks"
          :display="displayFields"
          @input-change="onInputChange"
          :edit="edit"
          :remote-option="remoteOption"
          :platform="platform"
          :preview="preview"
          :container-key="containerKey"
          :data-source-value="dataSourceValue"
          :event-function="eventFunction"
          :print-read="printRead"
          :form-component="$refs[formRef]"
          :group="''"
          :field-node="''"
        >
          <template v-slot:[blank.name]="scope" v-for="blank in blanks">
            <slot :name="blank.name" :model="scope.model"></slot>
          </template>
        </generate-report>

        <generate-inline
          v-else-if="item.type == 'inline'"
          :key="item.key"
          :model="models"
          :rules="rules"
          :element="item"
          :remote="remote"
          :blanks="blanks"
          :display="displayFields"
          @input-change="onInputChange"
          :edit="edit"
          :remote-option="remoteOption"
          :platform="platform"
          :preview="preview"
          :container-key="containerKey"
          :data-source-value="dataSourceValue"
          :event-function="eventFunction"
          :print-read="printRead"
          :form-component="$refs[formRef]"
          :group="''"
          :field-node="''"
        >
          <template v-slot:[blank.name]="scope" v-for="blank in blanks">
            <slot :name="blank.name" :model="scope.model"></slot>
          </template>
        </generate-inline>

        <generate-dialog
          v-else-if="item.type == 'dialog'"
          :key="item.key"
          :models.sync="models"
          :rules="rules"
          :element="item"
          :remote="remote"
          :blanks="blanks"
          :edit="edit"
          :remote-option="remoteOption"
          :platform="platform"
          :preview="preview"
          :container-key="containerKey"
          :data-source-value="dataSourceValue"
          :event-function="eventFunction"
          :print-read="printRead"
          :form-component="$refs[formRef]"
          :component-instance="instanceObject"
          :group="''"
          :field-node="''"
        >
          <template v-slot:[blank.name]="scope" v-for="blank in blanks">
            <slot :name="blank.name" :model="scope.model"></slot>
          </template>
        </generate-dialog>

        <generate-card
          v-else-if="item.type == 'card'"
          :key="item.key"
          :model="models"
          :rules="rules"
          :element="item"
          :remote="remote"
          :blanks="blanks"
          :display="displayFields"
          @input-change="onInputChange"
          :edit="edit"
          :remote-option="remoteOption"
          :platform="platform"
          :preview="preview"
          :container-key="containerKey"
          :data-source-value="dataSourceValue"
          :event-function="eventFunction"
          :print-read="printRead"
          :form-component="$refs[formRef]"
          :group="''"
          :field-node="''"
        >
          <template v-slot:[blank.name]="scope" v-for="blank in blanks">
            <slot :name="blank.name" :model="scope.model"></slot>
          </template>
        </generate-card>

        <generate-form-item
          v-else
          :key="item.key"
          :models="models"
          :rules="rules"
          :widget="item"
          :remote="remote"
          :blanks="blanks"
          :display="displayFields"
          @input-change="onInputChange"
          :edit="edit"
          :remote-option="remoteOption"
          :platform="platform"
          :preview="preview"
          :container-key="containerKey"
          :data-source-value="dataSourceValue"
          :event-function="eventFunction"
          :print-read="printRead"
          :form-component="$refs[formRef]"
          :group="''"
          :field-node="''"
        >
          <template v-slot:[blank.name]="scope" v-for="blank in blanks">
            <slot :name="blank.name" :model="scope.model"></slot>
          </template>
        </generate-form-item>
      </template>
    </el-form>
  </div>
</template>

<script>
import GenerateFormItem from './GenerateFormItem'
import GenerateColItem from './GenerateColItem'
import GenerateTabItem from './GenerateTabItem'
import GenerateReport from './GenerateReport'
import GenerateInline from './GenerateInline'
import GenerateCollapse from './GenerateCollapse.vue'
import GenerateDialog from './GenerateDialog.vue'
import GenerateCard from './GenerateCard.vue'
import {loadJs, updateStyleSheets, splitStyleSheets, clearStyleSheets, consoleError, getBindModels } from '../util/index.js'
import { updateClassName } from '../util/reuse-methods.js'
import { EventBus } from '../util/event-bus.js'
import _ from 'lodash'
import axios from 'axios'
import { exportPDF } from '../util/export.js'
import { ruleToFunction } from '../util/rule-funcs.js'
import { isExpression, extractExpression, executeExpression } from '../util/expression'

export default {
  name: 'fm-generate-form',
  components: {
    GenerateFormItem,
    GenerateColItem,
    GenerateTabItem,
    GenerateReport,
    GenerateInline,
    GenerateCollapse,
    GenerateDialog,
    GenerateCard
  },
  props: {
    data: {
      type: Object,
      default: () => ({
        "list": [],
        "config": {
          "labelWidth": 100,
          "labelPosition": "right",
          "size": "small",
          "customClass": "",
          "ui": "element",
          "layout": "horizontal"
        }
      })
    },
    remote: {
      type: Object,
      default: () => ({})
    },
    value: {
      type: Object,
      default: () => ({})
    },
    edit: {
      type: Boolean,
      default: true
    },
    printRead: {
      type: Boolean,
      default: false
    },
    remoteOption: {
      type: Object,
      default: () => ({})
    },
    preview: {
      type: Boolean,
      default: false
    },
    platform: {
      type: String,
      default: 'mobile'
    }
  },
  data () {
    return {
      formData: {},
      models: {},
      rules: {},
      blanks: [],
      displayFields: {},
      dataBindFields: {},
      generateShow: false,
      resetModels: {},
      formKey: Math.random().toString(36).slice(-8),
      formStyleKey: Math.random().toString(36).slice(-8),
      formValue: this.value,
      formShow: false,
      formRef: Math.random().toString(36).slice(-8) + 'Form',
      containerKey: Math.random().toString(36).slice(-8),
      dataSourceValue: [],
      eventFunction: {},
      instanceObject: {},
      dataSourceInterface: [],
      dynamicHideFields: {},
      dynamicValueData: [],
      dynamicValueFxInterface: {},
      dynamicOptionFxInterface: {},
      formItemContexts: {},
    }
  },
  computed: {
    formSize () {
      switch (this.data && this.formData.config && this.formData.config.size){
        case 'large': return 'large'
        case 'default': return 'small'
        case 'small': return 'mini'
        default: return 'small'
      }
    },
  },
  created () {
    this._initForm()
  },
  mounted () {
    this.$nextTick(() => {
      this.eventFunction.mounted && this.eventFunction['mounted']({})
    })
  },
  beforeDestroy () {
    let head = '.fm-' + this.formStyleKey + ' '
    clearStyleSheets(head)
  },
  provide() {
    return {
      'generateComponentInstance': this.generateComponentInstance,
      'deleteComponentInstance': this.deleteComponentInstance,
      'eventScriptConfig': this.getEventScriptConfig,
      'getFormComponent': this.getFormComponent,
      'onChange': this._changeFormValue,
      'onFormDisabled': this.disabled,
      'dynamicHideFields': this.dynamicHideFields,
      'onFormHide': this.hide,
      'onFormDisplay': this.display,
      'dynamicValueData': this.dynamicValueData,
      'dynamicOptionData': this.dynamicOptionData,
      'formContext': this,
      'generateFormItemContext': this.generateFormItemContext,
      'deleteFormItemContext': this.deleteFormItemContext,
      'sendRequest': this.sendRequest
    }
  },
  methods: {
    getFormComponent () {
      return this.$refs[this.formRef]
    },
    _changeFormValue (value, field) {
      this.models[field] = value

      this.$emit('on-change', field, value, this.models)
      this.$emit(`on-${field}-change`, value)
    },
    _initForm () {
      this.formShow = false
      this.formData = _.cloneDeep(this.data)

      this.models = {}
      this.rules = {}
      this.blanks = []
      this.displayFields = {}
      this.dataBindFields = {}
      this.resetModels = {}
      this.dataSourceValue = []
      this.eventFunction = []
      this.dataSourceInterface = []
      this.dynamicValueData.splice(0, this.dynamicValueData.length)
      Object.keys(this.dynamicHideFields).forEach(key => delete this.dynamicHideFields[key])
      this.dynamicValueFxInterface = {}
      this.dynamicOptionFxInterface = {}

      if (Object.keys(this.data).length) {
        this.generateModel(this.formData.list)
      } else {
        this.generateModel([])
      }

      this.models = {...this.models}

      return new Promise((resolve) => {
        this.$nextTick(() => {
          this.formShow = true

          if (this.formData.config && this.formData.config.styleSheets) {

            let head = '.fm-' + this.formStyleKey + ' '

            console.log('----head', head)

            updateStyleSheets(splitStyleSheets(this.formData.config.styleSheets), head)
          }

          this.loadDataSource()

          this.loadDynamicValueFx()

          this.loadEvents()

          this.$nextTick(() => {
            this.eventFunction['refresh'] && this.eventFunction['refresh']({})

            this.resetModels = _.cloneDeep(this.models)

            resolve()
          })
        })
      })
    },
    getEventScriptConfig () {
      return this.data?.config?.eventScript || []
    },
    loadEvents () {
      if (this.formData.config && this.formData.config.eventScript) {
        for (let i = 0; i < this.formData.config.eventScript.length; i++) {
          let currentScript = this.formData.config.eventScript[i]

          if (currentScript.type === 'rule') {
            // 加载异步方法
            console.log(ruleToFunction(currentScript.rules))
            this.eventFunction[currentScript.key] = new Function(`return (async () => {${ruleToFunction(currentScript.rules)}})()`).bind(this)
          } else {
            this.eventFunction[currentScript.key] = Function(currentScript.func).bind(this)
          }
        }
      }
    },
    triggerEvent (eventName, args) {
      if (this.formData.config && this.formData.config.eventScript) {
        let eventScript = this.formData.config.eventScript.find(item => item.name == eventName)

        if (eventScript) {
          return this.eventFunction[eventScript.key](args)
        }
      }
    },
    refreshDynamicValueAll () {
      this.refreshDynamicValue()
    },
    refreshDynamicValue (fields, args) {
      if (fields === undefined) {

        let refreshItems = []

        Object.keys(this.dynamicValueFxInterface).forEach(field => {

          if (this.formItemContexts[field]) {
            if (Array.isArray(this.formItemContexts[field])) {
              this.formItemContexts[field].forEach(fItem => {
                refreshItems.push(fItem)
              })
            } else {
              refreshItems.push(this.formItemContexts[field])
            }
          } else {
            let groupFormItems = []
            Object.keys(this.formItemContexts).forEach(key => {
              if (Array.isArray(this.formItemContexts[key])) {
                this.formItemContexts[key].forEach(fItem => {
                  if (fItem.groupNode == field) {
                    groupFormItems.push(fItem)
                  }
                })
              } else {
                if (this.formItemContexts[key].groupNode == field) {
                  groupFormItems.push(this.formItemContexts[key])
                }
              }
            })
            groupFormItems.forEach(fItem => {
              refreshItems.push(fItem)
            })
          }
        })

        for (let i = 0; i < this.dataSourceInterface.length; i++) {
          let curRequest = this.dataSourceInterface[i]

          if (curRequest.dynamicValueFields.length) {

            curRequest.dynamicValueFields.forEach(({field, struct}) => {
              if (this.formItemContexts[field]) {
                if (Array.isArray(this.formItemContexts[field])) {
                  this.formItemContexts[field].forEach(fItem => {
                    refreshItems.push(fItem)
                  })
                } else {
                  refreshItems.push(this.formItemContexts[field])
                }
              } else {
                let groupFormItems = []
                Object.keys(this.formItemContexts).forEach(key => {
                  if (Array.isArray(this.formItemContexts[key])) {
                    this.formItemContexts[key].forEach(fItem => {
                      if (fItem.groupNode == field) {
                        groupFormItems.push(fItem)
                      }
                    })
                  } else {
                    if (this.formItemContexts[key].groupNode == field) {
                      groupFormItems.push(this.formItemContexts[key])
                    }
                  }
                })
                groupFormItems.forEach(fItem => {
                  refreshItems.push(fItem)
                })
              }
            })
          }
        }

        return new Promise((resolve, reject) => {
          Promise.all(refreshItems.map(item => item.refreshDynamicValue())).then(values => {
            resolve(values)
          }).catch(e => {
            reject(e)
          })
        })
      }

      if (typeof fields === 'string') {
        fields = [fields]
      }
      let refreshItems = []
      const curArgs = (args && typeof args === 'object') ? {...args} : {}
      fields.forEach(field => {

        if (this.formItemContexts[field]) {
          if (Array.isArray(this.formItemContexts[field])) {
            this.formItemContexts[field].forEach(fItem => {
              refreshItems.push(fItem)
            })
          } else {
            refreshItems.push(this.formItemContexts[field])
          }
        } else {
          let groupFormItems = []
          Object.keys(this.formItemContexts).forEach(key => {
            if (this.formItemContexts[key].groupNode == field) {
              groupFormItems.push(this.formItemContexts[key])
            }
          })
          groupFormItems.forEach(fItem => {
            refreshItems.push(fItem)
          })
        }
      })

      return new Promise((resolve, reject) => {
        Promise.all(refreshItems.map(item => item.refreshDynamicValue(curArgs))).then(values => {
          resolve(values)
        }).catch(e => {
          reject(e)
        })
      })
    },
    loadDataSource () {
      for (let i = 0; i < this.dataSourceInterface.length; i++) {
        let curRequest = this.dataSourceInterface[i]
        let requestObj = this.formData.config.dataSource.find(item => item.key == curRequest.key)
        if (requestObj && requestObj.auto)
        requestObj.name && this.sendRequest(requestObj.name, {...curRequest.args}).then(data => {
          let curArgs = {...curRequest.args}
          for (let key in curArgs) {
          if (isExpression(curArgs[key])) {
              curArgs[key] = executeExpression(extractExpression(curArgs[key]), {}, this)
            }
          }

          curRequest.fields.forEach(field => {
            let curKey = field + '.' + curRequest.key
            let sourceValue = this.dataSourceValue.find(item => item.key === curKey)

            if (sourceValue) {
              sourceValue.value = data
            } else {
              this.dataSourceValue.push({
                key: curKey,
                args: curArgs,
                value: data
              })
            }
          })

          curRequest.dynamicValueFields.forEach(({field, struct}) => {
            let curKey = field + '.' + curRequest.key

            let sourceValue = this.dynamicValueData.find(item => item.key === curKey)

            if (sourceValue) {
              sourceValue.value = data
            } else {
              this.dynamicValueData.push({
                key: curKey,
                args: curArgs,
                value: data
              })
            }
          })

        })
      }
      // 处理需要初始化请求但没有进行绑定的数据源
      if (this.formData.config?.dataSource?.length > 0) {
        for (let i = 0; i < this.formData.config.dataSource.length; i++) {
          let currentDataSource = this.formData.config.dataSource[i]

          if (currentDataSource.auto && this.dataSourceInterface.findIndex(item => item.key == currentDataSource.key) < 0) {
            this.sendRequest(currentDataSource.name, {})
          }
        }
      }
    },
    loadDynamicValueFx () {
      Object.keys(this.dynamicValueFxInterface).forEach(field => {
        if (this.formItemContexts[field]) {
          if (Array.isArray(this.formItemContexts[field])) {
            this.formItemContexts[field].forEach(fItem => {
              fItem.refreshDynamicValue()
            })
          } else {
            this.formItemContexts[field].refreshDynamicValue()
          }
        } else {
          let groupFormItems = []
          Object.keys(this.formItemContexts).forEach(key => {
            if (this.formItemContexts[key].groupNode == field) {
              groupFormItems.push(this.formItemContexts[key])
            }
          })
          groupFormItems.forEach(fItem => {
            fItem.refreshDynamicValue()
          })
        }
      })
    },
    refreshFieldOptionData (fields, args) {
      if (fields === undefined) return Promise.resolve([])
      if (typeof fields === 'string') {
        fields = [fields]
      }

      let refreshInstances = []
      const curArgs = (args && typeof args === 'object') ? {...args} : {}
      fields.forEach(field => {
        if (this.instanceObject[field]) {
          if (Array.isArray(this.instanceObject[field])) {
            this.instanceObject[field].forEach(fItem => {
              fItem?.$parent && refreshInstances.push(fItem?.$parent)
            })
          } else {
            this.instanceObject[field]?.$parent && refreshInstances.push(this.instanceObject[field]?.$parent)
          }
        } else {
          let groupFormItems = []
          Object.keys(this.instanceObject).forEach(key => {

            if (Array.isArray(this.instanceObject[key])) {
              this.instanceObject[key].forEach(fItem => {
                if (fItem?.$parent?.groupNode == field) {
                  groupFormItems.push(fItem)
                }
              })
            } else {
              if (this.instanceObject[key]?.$parent?.groupNode == field) {
                groupFormItems.push(this.instanceObject[key])
              }
            }
          })
          console.log('groupFormItems', groupFormItems)
          groupFormItems.forEach(fItem => {
            fItem?.$parent && refreshInstances.push(fItem?.$parent)
          })
        }
      })

      return new Promise((resolve, reject) => {
        Promise.all(refreshInstances.map(item => item.refreshOptionData(curArgs))).then(values => {
          resolve(values)
        }).catch(e => {
          reject(e)
        })
      })
    },
    refreshFieldDataSource (field, args) {
      let curRequest = this.dataSourceInterface.find(item => item.fields.includes(field))

      return new Promise((resolve) => {
        if (curRequest) {
          let requestName = this.formData.config.dataSource.find(item => item.key == curRequest.key)?.name
          requestName && this.sendRequest(requestName, {...curRequest.args, ...args}).then(data => {
            let curKey = field + '.' + curRequest.key
            let sourceValue = this.dataSourceValue.find(item => item.key === curKey)

            if (sourceValue) {
              sourceValue.value = data
            } else {
              this.dataSourceValue.push({
                key: curKey,
                value: data
              })
            }

            resolve(data)
          })
        } else {
          resolve()
        }
      })
    },

    getFieldDataSource (field) {
      let curRequest = this.dataSourceInterface.find(item => item.fields.includes(field))

      if (curRequest) {
        let curKey = field + '.' + curRequest.key

        let sourceValue = this.dataSourceValue.find(item => item.key === curKey)

        if (sourceValue) {
          return sourceValue.value
        }
      }

      return null
    },

    sendRequest(name, args = {}) {
      return new Promise((resolve, reject) => {
        let currentDataSource = this.formData.config.dataSource.find(item => item.name === name)

        if (!currentDataSource) {
          currentDataSource = this.formData.config.dataSource.find(item => item.key === name)
        }

        if (currentDataSource) {
          for (let key in args) {
            if (isExpression(args[key])) {
              args[key] = executeExpression(extractExpression(args[key]), {}, this)
            }
          }

          let options = {
            method: currentDataSource.method,
            url: currentDataSource.url,
            headers: {},
            params: {},
            data: {}
          }
console.log(currentDataSource,'headers')
          let optionsHeaders = {}
          currentDataSource.headers && Object.keys(currentDataSource.headers).forEach(key => {
            if (isExpression(currentDataSource.headers[key])) {
              optionsHeaders[key] = executeExpression(extractExpression(currentDataSource.headers[key]),args, this)
            } else {
              optionsHeaders[key] = currentDataSource.headers[key]
            }
          })

          Object.keys(optionsHeaders).length && (options['headers'] = optionsHeaders)

          let optionsParams = {}
          currentDataSource.params && Object.keys(currentDataSource.params).forEach(key => {
            if (isExpression(currentDataSource.params[key])) {
              optionsParams[key] = executeExpression(extractExpression(currentDataSource.params[key]),args, this)
            } else {
              optionsParams[key] = currentDataSource.params[key]
            }
          })

          if (options.method === 'POST' || options.method === 'PUT') {
            options['data'] = optionsParams
          } else {
            options['params'] = optionsParams
          }

          //请求发送前处理函数
          if (currentDataSource.requestFunc) {
            const requestDynamicFunc = Function('config', 'args', currentDataSource.requestFunc).bind(this)

            options = requestDynamicFunc(options, args)
          }

          axios(options).then(res => {

            let data = res

            if (currentDataSource.responseFunc) {
              const dynamicFunc = Function('res', 'args', currentDataSource.responseFunc).bind(this)

              data = dynamicFunc(res.data, args)

              resolve(data)
            } else {
              resolve(res.data)
            }
          }).catch((error) => {
            //请求错误处理函数
            if (currentDataSource.errorFunc) {
              const errorDynamicFunc = Function('error', currentDataSource.errorFunc).bind(this)

              errorDynamicFunc(error)
            }

            reject(error)
          })
        }
      })
    },
    generateSubformModel (subName, genList, dataBindFields) {
      for (let i = 0; i < genList.length; i++) {

        if (genList[i].type === 'grid') {
          genList[i].columns.forEach(item => {
            this.generateSubformModel(subName, item.list, dataBindFields)
          })
        } else if (genList[i].type === 'tabs') {
          genList[i].tabs.forEach(item => {
            this.generateSubformModel(subName, item.list, dataBindFields)
          })
        } else if (genList[i].type === 'collapse') {
          genList[i].tabs.forEach(item => {
            this.generateSubformModel(subName, item.list, dataBindFields)
          })
        } else if (genList[i].type === 'report') {
          genList[i].rows.forEach(row => {
            row.columns.forEach(column => {
              this.generateSubformModel(subName, column.list, dataBindFields)
            })
          })
        } else if (genList[i].type === 'inline') {
          this.generateSubformModel(subName, genList[i].list, dataBindFields)
        } else if (genList[i].type === 'card') {
          this.generateSubformModel(subName, genList[i].list, dataBindFields)
        } else {

          if (genList[i].type === 'blank') {
            this.blanks.push({
              name: genList[i].model
            })
          }

          if (genList[i].options.dataBind) {
            if (['subform', 'group', 'table'].includes(genList[i].type)) {
              dataBindFields[genList[i].model] = {}
            } else {
              dataBindFields[genList[i].model] = true
            }
          }

          genList[i].tableColumns && genList[i].tableColumns.length && genList[i].tableColumns.forEach(item => {
            if (item.type === 'blank') {
              this.blanks.push({
                name: item.model
              })
            }

            if (item.options.dataBind && genList[i].options.dataBind) {
              dataBindFields[genList[i].model][item.model] = true
            }

            // 处理 rules
            this._generateRules(`${subName}.${genList[i].model}.${item.model}`, item.rules)

            // 处理子表单中的DataSource
            this._generateDataSource(item, `${subName}.${genList[i].model}.${item.model}`)
          })

          if (genList[i].type == 'subform') {
            this.generateSubformModel(`${subName}.${genList[i].model}`, genList[i].list, dataBindFields[genList[i].model] || {})
          }

          if (genList[i].type == 'group') {
            this.generateGroupModel(`${subName}.${genList[i].model}`, genList[i].list, dataBindFields[genList[i].model] || {})
          }

          // 处理 rules
          this._generateRules(`${subName}.${genList[i].model}`, genList[i].rules)

          // 处理子表单中的DataSource
          this._generateDataSource(genList[i], `${subName}.${genList[i].model}`)
        }
      }
    },
    generateDialogModel (dialogName, genList, dataBindFields) {
      for (let i = 0; i < genList.length; i++) {

        if (genList[i].type === 'grid') {
          genList[i].columns.forEach(item => {
            this.generateDialogModel(dialogName, item.list, dataBindFields)
          })
        } else if (genList[i].type === 'tabs') {
          genList[i].tabs.forEach(item => {
            this.generateDialogModel(dialogName, item.list, dataBindFields)
          })
        } else if (genList[i].type === 'collapse') {
          genList[i].tabs.forEach(item => {
            this.generateDialogModel(dialogName, item.list, dataBindFields)
          })
        } else if (genList[i].type === 'report') {
          genList[i].rows.forEach(row => {
            row.columns.forEach(column => {
              this.generateDialogModel(dialogName, column.list, dataBindFields)
            })
          })
        } else if (genList[i].type === 'inline') {
          this.generateDialogModel(dialogName, genList[i].list, dataBindFields)
        } else if (genList[i].type === 'card') {
          this.generateDialogModel(dialogName, genList[i].list, dataBindFields)
        } else {

          if (genList[i].type === 'blank') {
            this.blanks.push({
              name: genList[i].model
            })
          }

          if (genList[i].options.dataBind) {
            if (['subform', 'group', 'table'].includes(genList[i].type)) {
              dataBindFields[genList[i].model] = {}
            } else {
              dataBindFields[genList[i].model] = true
            }
          }

          if (genList[i].type == 'subform') {
            this.generateSubformModel(`${dialogName}.${genList[i].model}`, genList[i].list, dataBindFields[genList[i].model] || {})
          }

          if (genList[i].type == 'group') {
            this.generateGroupModel(`${dialogName}.${genList[i].model}`, genList[i].list, dataBindFields[genList[i].model] || {})
          }

          genList[i].tableColumns && genList[i].tableColumns.length && genList[i].tableColumns.forEach(item => {
            if (item.type === 'blank') {
              this.blanks.push({
                name: item.model
              })
            }

            if (item.options.dataBind && genList[i].options.dataBind) {
              dataBindFields[genList[i].model][item.model] = true
            }

            // 处理 rules
            this._generateRules(`${dialogName}.${genList[i].model}.${item.model}`, item.rules)

            // 处理子表单中的DataSource
            this._generateDataSource(item, `${dialogName}.${genList[i].model}.${item.model}`)
          })

          this._generateRules(`${dialogName}.${genList[i].model}`, genList[i].rules)

          // 处理弹框中的DataSource
          this._generateDataSource(genList[i], `${dialogName}.${genList[i].model}`)
        }
      }
    },
    generateGroupModel (groupName, genList, dataBindFields) {
      for (let i = 0; i < genList.length; i++) {

        if (genList[i].type === 'grid') {
          genList[i].columns.forEach(item => {
            this.generateGroupModel(groupName, item.list, dataBindFields)
          })
        } else if (genList[i].type === 'tabs') {
          genList[i].tabs.forEach(item => {
            this.generateGroupModel(groupName, item.list, dataBindFields)
          })
        } else if (genList[i].type === 'collapse') {
          genList[i].tabs.forEach(item => {
            this.generateGroupModel(groupName, item.list, dataBindFields)
          })
        } else if (genList[i].type === 'report') {
          genList[i].rows.forEach(row => {
            row.columns.forEach(column => {
              this.generateGroupModel(groupName, column.list, dataBindFields)
            })
          })
        } else if (genList[i].type === 'inline') {
          this.generateGroupModel(groupName, genList[i].list, dataBindFields)
        } else if (genList[i].type === 'card') {
          this.generateGroupModel(groupName, genList[i].list, dataBindFields)
        } else {

          if (genList[i].type === 'blank') {
            this.blanks.push({
              name: genList[i].model
            })
          }

          if (genList[i].options.dataBind) {
            if (['subform', 'group', 'table'].includes(genList[i].type)) {
              dataBindFields[genList[i].model] = {}
            } else {
              dataBindFields[genList[i].model] = true
            }
          }

          if (genList[i].type == 'subform') {
            this.generateSubformModel(`${groupName}.${genList[i].model}`, genList[i].list, dataBindFields[genList[i].model] || {})
          }

          if (genList[i].type == 'group') {
            this.generateGroupModel(`${groupName}.${genList[i].model}`, genList[i].list, dataBindFields[genList[i].model] || {})
          }

          genList[i].tableColumns && genList[i].tableColumns.length && genList[i].tableColumns.forEach(item => {
            if (item.type === 'blank') {
              this.blanks.push({
                name: item.model
              })
            }

            if (item.options.dataBind && genList[i].options.dataBind) {
              dataBindFields[genList[i].model][item.model] = true
            }

            // 处理 rules
            this._generateRules(`${groupName}.${genList[i].model}.${item.model}`, item.rules)

            // 处理子表单中的DataSource
            this._generateDataSource(item, `${groupName}.${genList[i].model}.${item.model}`)
          })

          this._generateRules(`${groupName}.${genList[i].model}`, genList[i].rules)

          // 处理弹框中的DataSource
          this._generateDataSource(genList[i], `${groupName}.${genList[i].model}`)
        }
      }
    },
    generateModel (genList) {
      for (let i = 0; i < genList.length; i++) {

        if (genList[i].type === 'grid') {
          this.displayFields[genList[i].model] = !genList[i].options.hidden

          genList[i].columns.forEach(item => {
            this.generateModel(item.list)
          })
        } else if (genList[i].type === 'tabs') {
          genList[i].tabs.forEach(item => {
            this.generateModel(item.list)
          })

          this.displayFields[genList[i].model] = !genList[i].options.hidden
        } else if (genList[i].type === 'collapse') {
          genList[i].tabs.forEach(item => {
            this.generateModel(item.list)
          })

          this.displayFields[genList[i].model] = !genList[i].options.hidden
        } else if (genList[i].type === 'report') {
          genList[i].rows.forEach(row => {
            row.columns.forEach(column => {
              this.generateModel(column.list)
            })
          })

          this.displayFields[genList[i].model] = !genList[i].options.hidden
        } else if (genList[i].type === 'inline') {
          this.generateModel(genList[i].list)

          this.displayFields[genList[i].model] = !genList[i].options.hidden
        } else if (genList[i].type === 'card') {
          this.generateModel(genList[i].list)

          this.displayFields[genList[i].model] = !genList[i].options.hidden
        } else {
          if (Object.keys(this.formValue).indexOf(genList[i].model) >= 0) {
            this.models[genList[i].model] = this.formValue[genList[i].model]

            this.displayFields[genList[i].model] = !genList[i].options.hidden

            if (genList[i].type === 'blank') {
              this.blanks.push({
                name: genList[i].model
              })
            }

          } else {
            if (genList[i].type === 'blank') {
              // bound the default value
              this.models[genList[i].model] = genList[i].options.defaultType === 'String' ? '' : (genList[i].options.defaultType === 'Object' ? {} : [])

              this.displayFields[genList[i].model] = !genList[i].options.hidden

              this.blanks.push({
                name: genList[i].model
              })
            } else {
              this.$set(this.models, genList[i].model, genList[i].options.defaultValue)

              this.displayFields[genList[i].model] = !genList[i].options.hidden
            }
          }

          if ((Object.keys(genList[i].options).indexOf('dataBind') < 0 || genList[i].options.dataBind) && genList[i].key && genList[i].model) {

            if (['subform', 'table', 'dialog', 'group'].includes(genList[i].type)) {
              this.dataBindFields[genList[i].model] = {}
            } else {
              this.dataBindFields[genList[i].model] = true
            }
          }

          if (genList[i].type == 'subform') {
            this.generateSubformModel(genList[i].model, genList[i].list, this.dataBindFields[genList[i].model] || {})
          }

          if (genList[i].type == 'dialog') {
            this.generateDialogModel(genList[i].model, genList[i].list, this.dataBindFields[genList[i].model] || {})
          }

          if (genList[i].type == 'group') {
            this.generateGroupModel(genList[i].model, genList[i].list, this.dataBindFields[genList[i].model] || {})
          }

          genList[i].tableColumns && genList[i].tableColumns.length && genList[i].tableColumns.forEach(item => {
            if (item.type === 'blank') {
              this.blanks.push({
                name: item.model
              })
            }

            if (item.options.dataBind && genList[i].options.dataBind) {
              this.dataBindFields[genList[i].model][item.model] = true
            }

            // 处理 rules
            this._generateRules(`${genList[i].model}.${item.model}`, item.rules)

            // 处理子表单中的DataSource
            this._generateDataSource(item, `${genList[i].model}.${item.model}`)
          })

          this._generateRules(genList[i].model, genList[i].rules)

          // 处理DataSource
          this._generateDataSource(genList[i], genList[i].model)
        }
      }
    },
    _generateDataSource (element, model) {
      if (element.options.remote && element.options.remoteType === 'datasource' && element.options.remoteDataSource) {
        this._setDataSourceInterface(model, element.options.remoteArgs, element.options.remoteDataSource)
      }
      if (element.options.remote && element.options.remoteType === 'fx' && element.options.remoteFx) {
        this.dynamicOptionFxInterface[model] = element.options.remoteFx
      }
      if ((element.type == 'imgupload' || element.type == 'fileupload')
        && element.options.tokenType == 'datasource' && element.options.tokenDataSource
      ) {
        this._setDataSourceInterface(model, element.options.remoteArgs, element.options.tokenDataSource)
      }
      if (element.options.isDynamicValue && element.options.dynamicValueType === 'datasource' && element.options.dynamicValueDataSource) {
        this._setDynamicValueInterface(model, element.options.dynamicValueArgs, element.options.dynamicValueDataSource, element.options.dynamicValueStruct)
      }
      if (element.options.isDynamicValue && element.options.dynamicValueType === 'fx') {
        this.dynamicValueFxInterface[model] = element.options.dynamicValueFx
      }
    },
    _generateRules (model, rules) {
      if (this.rules[model]) {
        this.rules[model] = [
          ...this.rules[model],
          ...(rules ? rules.map(im => {
            if (im.pattern) {
              return {...im, pattern: eval(im.pattern)}
            } else if (im.func) {

              const validatorFunc = Function('rule', 'value', 'callback', im.func).bind(this)

              return {...im, validator: validatorFunc}
            } else {
              return {...im}
            }
          }) : [])
        ]
      } else {

        this.rules[model] = [
          ...(rules ? rules.map(im => {
            if (im.pattern) {
              return {...im, pattern: eval(im.pattern)}
            } else if (im.func) {
              const validatorFunc = Function('rule', 'value', 'callback', im.func).bind(this)

              return {...im, validator: validatorFunc}
            } else {
              return {...im}
            }
          }) : [])
        ]
      }
    },
    _setDataSourceInterface (field, args, key) {
      let argsObj
      if (typeof args == 'string') {
        argsObj =  (new Function('"use strict";return (' + (args || '{}') + ')').bind(this))()
      } else {
        argsObj =  {...args}
      }

      for (let key in argsObj) {
        if (isExpression(argsObj[key])) {
          argsObj[key] = executeExpression(extractExpression(argsObj[key]), {}, this)
        }
      }

      let findCurInterfaceIndex = this.dataSourceInterface.findIndex(item => item.key == key && _.isEqual(item.args, argsObj))

      if (findCurInterfaceIndex >= 0) {
        this.dataSourceInterface[findCurInterfaceIndex].fields.push(field)
      } else {
        this.dataSourceInterface.push({
          key: key,
          args: argsObj,
          fields: [field],
          dynamicValueFields: []
        })
      }
    },
    _setDynamicValueInterface (field, args, key, struct) {
      let findCurInterfaceIndex = this.dataSourceInterface.findIndex(item => item.key == key && _.isEqual(item.args, args))

      if (findCurInterfaceIndex >= 0) {
        this.dataSourceInterface[findCurInterfaceIndex].dynamicValueFields.push({field, struct})
      } else {
        this.dataSourceInterface.push({
          key,
          args,
          dynamicValueFields: [{field, struct}],
          fields: []
        })
      }
    },
    _setSubDisabled (genList, fields, disabled) {
      for (let i = 0; i < genList.length; i++) {
        if (genList[i].type === 'grid') {
          genList[i].columns.forEach(item => {
            this._setSubDisabled(item.list, fields, disabled)
          })
        } else if (genList[i].type === 'tabs') {
          genList[i].tabs.forEach(item => {
            this._setSubDisabled(item.list, fields, disabled)
          })
        } else if (genList[i].type === 'collapse') {
          genList[i].tabs.forEach(item => {
            this._setSubDisabled(item.list, fields, disabled)
          })
        } else if (genList[i].type === 'report') {
          genList[i].rows.forEach(row => {
            row.columns.forEach(column => {
              this._setSubDisabled(column.list, fields, disabled)
            })
          })
        } else if (genList[i].type === 'inline') {
          this._setSubDisabled(genList[i].list, fields, disabled)
        } else if (genList[i].type === 'card') {
          this._setSubDisabled(genList[i].list, fields, disabled)
        } else {

          if (fields.length === 1) {
            if (genList[i].model === fields[0]) {
              this.$set(genList[i].options, 'disabled', disabled)
            }
          } else {
            if (genList[i].model !== fields[0]) continue
            let newFields = [...fields]
            newFields.splice(0, 1)
            if (genList[i].type === 'table') {
              this._setSubDisabled(genList[i].tableColumns, newFields, disabled)
            }
            if (genList[i].type === 'subform') {
              this._setSubDisabled(genList[i].list, newFields, disabled)
            }
            if (genList[i].type === 'group') {
              this._setSubDisabled(genList[i].list, newFields, disabled)
            }
            if (genList[i].type === 'dialog') {
              this._setSubDisabled(genList[i].list, newFields, disabled)
            }
          }
        }
      }
    },
    _setSubOptions (genList, fields, opts) {
      for (let i = 0; i < genList.length; i++) {
        if (fields.length === 1) {
          if (genList[i].model === fields[0]) {
            Object.keys(opts).forEach(key => {
              this.$set(genList[i].options, key, opts[key])
            })
          } else{
            if (genList[i].type === 'grid') {
              genList[i].columns.forEach(item => {
                this._setSubOptions(item.list, fields, opts)
              })
            } else if (genList[i].type === 'tabs') {
              genList[i].tabs.forEach(item => {
                this._setSubOptions(item.list, fields, opts)
              })
            } else if (genList[i].type === 'collapse') {
              genList[i].tabs.forEach(item => {
                this._setSubOptions(item.list, fields, opts)
              })
            } else if (genList[i].type === 'report') {
              genList[i].rows.forEach(row => {
                row.columns.forEach(column => {
                  this._setSubOptions(column.list, fields, opts)
                })
              })
            } else if (genList[i].type === 'inline') {
              this._setSubOptions(genList[i].list, fields, opts)
            } else if (genList[i].type === 'card') {
              this._setSubOptions(genList[i].list, fields, opts)
            }
          }
        } else {

          if (genList[i].type === 'grid') {
            genList[i].columns.forEach(item => {
              this._setSubOptions(item.list, fields, opts)
            })
          } else if (genList[i].type === 'tabs') {
            genList[i].tabs.forEach(item => {
              this._setSubOptions(item.list, fields, opts)
            })
          } else if (genList[i].type === 'collapse') {
            genList[i].tabs.forEach(item => {
              this._setSubOptions(item.list, fields, opts)
            })
          } else if (genList[i].type === 'report') {
            genList[i].rows.forEach(row => {
              row.columns.forEach(column => {
                this._setSubOptions(column.list, fields, opts)
              })
            })
          } else if (genList[i].type === 'inline') {
            this._setSubOptions(genList[i].list, fields, opts)
          } else if (genList[i].type === 'card') {
            this._setSubOptions(genList[i].list, fields, opts)
          } else {
            if (genList[i].model !== fields[0]) continue

            let newFields = [...fields]
            newFields.splice(0, 1)

            if (genList[i].type === 'table') {
              this._setSubOptions(genList[i].tableColumns, newFields, opts)
            }
            if (genList[i].type === 'subform') {
              this._setSubOptions(genList[i].list, newFields, opts)
            }
            if (genList[i].type === 'group') {
              this._setSubOptions(genList[i].list, newFields, opts)
            }
            if (genList[i].type === 'dialog') {
              this._setSubOptions(genList[i].list, newFields, opts)
            }
          }
        }
      }
    },
    _getSubOptions(genList, fields) {
      for (let i = 0; i < genList.length; i++) {
        if (fields.length === 1) {
          if (genList[i].model === fields[0]) {
            return genList[i].options
          } else {
            if (genList[i].type === 'grid') {
              for (const item of genList[i].columns) {
                const options = this._getSubOptions(item.list, fields)
                if (options) return options
              }
            } else if (genList[i].type === 'tabs') {
              for (const item of genList[i].tabs) {
                const options = this._getSubOptions(item.list, fields)
                if (options) return options
              }
            } else if (genList[i].type === 'collapse') {
              for (const item of genList[i].tabs) {
                const options = this._getSubOptions(item.list, fields)
                if (options) return options
              }
            } else if (genList[i].type === 'report') {
              for (const row of genList[i].rows) {
                for (const column of row.columns) {
                  const options = this._getSubOptions(column.list, fields)
                  if (options) return options
                }
              }
            } else if (genList[i].type === 'inline') {
              const options = this._getSubOptions(genList[i].list, fields)
              if (options) return options
            } else if (genList[i].type === 'card') {
              const options = this._getSubOptions(genList[i].list, fields)
              if (options) return options
            }
          }
        } else {

          if (genList[i].type === 'grid') {
            for (const item of genList[i].columns) {
              const options = this._getSubOptions(item.list, fields)
              if (options) return options
            }
          } else if (genList[i].type === 'tabs') {
            for (const item of genList[i].tabs) {
              const options = this._getSubOptions(item.list, fields)
              if (options) return options
            }
          } else if (genList[i].type === 'collapse') {
            for (const item of genList[i].tabs) {
              const options = this._getSubOptions(item.list, fields)
              if (options) return options
            }
          } else if (genList[i].type === 'report') {
            for (const row of genList[i].rows) {
              for (const column of row.columns) {
                const options = this._getSubOptions(column.list, fields)
                if (options) return options
              }
            }
          } else if (genList[i].type === 'inline') {
            const options = this._getSubOptions(genList[i].list, fields)
            if (options) return options
          } else if (genList[i].type === 'card') {
            const options = this._getSubOptions(genList[i].list, fields)
            if (options) return options
          } else {
            if (genList[i].model !== fields[0]) continue

            let newFields = [...fields]
            newFields.splice(0, 1)

            if (genList[i].type === 'table') {
              const options = this._getSubOptions(genList[i].tableColumns, newFields)
              if(options) return options
            }
            if (genList[i].type === 'subform') {
              const options = this._getSubOptions(genList[i].list, newFields)
              if (options) return options
            }
            if (genList[i].type === 'group') {
              const options = this._getSubOptions(genList[i].list, newFields)
              if (options) return options
            }
            if (genList[i].type === 'dialog') {
              const options = this._getSubOptions(genList[i].list, newFields)
              if (options) return options
            }
          }
        }
      }
      return null
    },
    validate (fields) {
      if (typeof fields === 'string') {
        fields = [fields]
      }
      return new Promise((resolve, reject) => {
        if (fields && fields.length) {
          this.$refs[this.formRef].validateField(fields, (error) => {
            if (!error) {
              resolve()
            } else {
              reject(error)
            }
          })
        } else {
          this.$refs[this.formRef].validate((valid, error) => {
            if (valid) {
              resolve()
            } else {
              reject(error)
            }
          })
        }
      })
    },
    getData (isValidate = true) {
      return new Promise((resolve, reject) => {
        if (isValidate) {
          this.$refs[this.formRef].validate(valid => {
            if (valid) {
              resolve(getBindModels(this.models, this.dataBindFields))
            } else {
              reject(new Error(this.$t('fm.message.validError')).message)
            }
          })
        } else {
          resolve(getBindModels(this.models, this.dataBindFields))
        }
      })
    },
    reset () {
      return new Promise((resolve) => {
        this.setData(_.cloneDeep(this.resetModels)).then(() => {
          setTimeout(() => {
            this.$refs[this.formRef].clearValidate()
            resolve()
          })
        })
      })
    },
    onInputChange (value, field) {
      this.$emit('on-change', field, value, this.models)
      this.$emit(`on-${field}-change`, value)
    },
    display (fields) {
      if (typeof fields === 'string') {
        fields = [fields]
      }
      fields.forEach(field => {
        this.$set(this.dynamicHideFields, field, false)
      })
    },
    hide (fields) {
      if (typeof fields === 'string') {
        fields = [fields]
      }
      fields.forEach(field => {
        this.$set(this.dynamicHideFields, field, true)
      })
    },
    disabled (fields, disabled) {
      if (typeof fields === 'string') {
        fields = [fields]
      }
      fields.forEach(item => {
        let currentComponent = this.instanceObject[item]
        if (currentComponent) {
          if (Array.isArray(currentComponent)) {
            currentComponent.forEach(cc => {
              cc.$parent?.disabledElement(disabled)
            })
          } else {
            currentComponent.$parent?.disabledElement(disabled)
          }
        } else {
          this._setSubDisabled(this.formData.list, item.split('.'), disabled)
        }
      })
    },
    addClassName (fields, className) {
      if (typeof fields === 'string') {
        fields = [fields]
      }
      fields.forEach(item => {
        updateClassName(this.formData.list, item.split('.'), className, 'add')
      })
    },
    removeClassName (fields, className) {
      if (typeof fields === 'string') {
        fields = [fields]
      }
      fields.forEach(item => {
        updateClassName(this.formData.list, item.split('.'), className, 'remove')
      })
    },
    async refresh () {
      await this._initForm()
    },
    setData (value) {
      const _setNestedValue = (currentObj, keys, value) => {
        const key = keys.shift()

        if (keys.length === 0) {
          this.$set(currentObj, key, value)
        } else {
          if (key in currentObj) {
            if (Array.isArray(currentObj[key])) {
              if (Number.isNaN(Number(keys[0]))) {
                currentObj[key].forEach(cur => {
                  _setNestedValue(cur, [...keys], value)
                })
              } else {
                const indexKey = keys.shift()
                currentObj[key].length > Number(indexKey) && _setNestedValue(currentObj[key][Number(indexKey)], [...keys], value)
              }
            } else {
              _setNestedValue(currentObj[key], [...keys], value)
            }
          }
        }
      }

      return new Promise((resolve) => {
        this.$nextTick(() => {
          Object.keys(value).forEach(item => {
            _setNestedValue(this.models, item.split('.'), value[item])
          })
          resolve()
        })
      })
    },
    getComponent (name) {
      if (name === undefined) {
        return this.instanceObject
      }
      if (this.instanceObject[name]) {
        return this.instanceObject[name]
      } else {
        consoleError('No component instance found with ' + name)
        return null
      }
    },
    getValues () {
      return _.cloneDeep(this.models)
    },
    getValue (fieldName) {
      const resModels = _.cloneDeep(this.models)

      let fieldArray = fieldName.split('.')

      const _getFieldRes = (res, array) => {
        if (array.length === 1) {
          return res[array[0]]
        } else {
          let newRes = res[array[0]]

          let newFields = [...array]
          newFields.splice(0, 1)

          return _getFieldRes(newRes, newFields)
        }
      }

      return _getFieldRes(resModels, fieldArray)
    },
    setRules (field, rules) {

      this.$set(this.rules, field, [...rules])

      this.$nextTick(() => {
        this.$refs[this.formRef].clearValidate(field)
      })
    },
    setOptions (fields, options) {
      if (typeof fields === 'string') {
        fields = [fields]
      }
      fields.forEach(item => {
        this._setSubOptions(this.formData.list, item.split('.'), options)
      })
    },
    getOptions (field, key) {
      const result = this._getSubOptions(this.formData.list, field.split('.'))

      if (key) {
        return result[key]
      } else {
        return result
      }
    },
    generateComponentInstance (key, instance) {
      if (this.instanceObject[key]) {
        if (Array.isArray(this.instanceObject[key])) {
          this.instanceObject[key] = [...this.instanceObject[key], instance]
        } else {
          this.instanceObject[key] = [this.instanceObject[key], instance]
        }
      } else {
        this.instanceObject[key] = instance
      }
    },
    deleteComponentInstance (key) {
      if (this.instanceObject[key]) {
        delete this.instanceObject[key]
      }
    },
    generateFormItemContext (key, instance) {
      if (this.formItemContexts[key]) {
        if (Array.isArray(this.formItemContexts[key])) {
          this.formItemContexts[key] = [...this.formItemContexts[key], instance]
        } else {
          this.formItemContexts[key] = [this.formItemContexts[key], instance]
        }
      } else {
        this.formItemContexts[key] = instance
      }
    },
    deleteFormItemContext (key) {
      if (this.formItemContexts[key]) {
        delete this.formItemContexts[key]
      }
    },
    setOptionData (fields, data) {
      if (typeof fields === 'string') {
        fields = [fields]
      }
      fields.forEach(field => {
        const curRef = this.instanceObject[field]

        if (Array.isArray(curRef)) {
          curRef.forEach(item => {
            item?.$parent?.loadOptions(data)
          })
        } else {
          curRef?.$parent?.loadOptions(data)
        }
      })
    },
    getOptionData (field) {
      const curRef = this.instanceObject[field]
      return curRef?.$parent?.getOptions()
    },
    exportPDF () {
      if (this.printRead) {
        return exportPDF(document.querySelector('.fm-'+this.formStyleKey))
      } else {
        return Promise.reject()
      }
    },
    print () {
      if (this.printRead) {
        return new Promise((resolve, reject) => {
          exportPDF(document.querySelector('.fm-'+this.formStyleKey)).then(data => {
            const pdfUrl = URL.createObjectURL(data)

            const iframeclass = 'fmiframe-print-container'

            Array.from(document.getElementsByClassName(iframeclass)).forEach(item => {
              document.body.removeChild(item)
            })

            let iframe = document.createElement('iframe')

            iframe.style.display = 'none'
            iframe.src = pdfUrl
            iframe.className = iframeclass

            iframe.onload = function() {
              setTimeout(() => {

                iframe.contentWindow.print()

                resolve(data)
              }, 100)
            }

            document.body.appendChild(iframe)
          })
        })
      } else {
        return Promise.reject('Set the print-read attribute to true for printing.')
      }
    },
    openDialog (dialogField) {
      const dialogComponent = this.getComponent(dialogField)

      if (dialogComponent) {
        dialogComponent.open()
      }
    },
    closeDialog (dialogField) {
      const dialogComponent = this.getComponent(dialogField)

      if (dialogComponent) {
        dialogComponent.close()
      }
    },
    getDynamicValue (key) {
      return this.dynamicValueData.find(item => item.key == key)
    }
  }
}
</script>

<style lang="scss">
</style>
