<template>
  <van-form
    ref="form"
    :colon="colon"
    :label-width="labelWidth"
    :label-align="labelPosition"
    :input-align="inputAlign"
  >
    <template v-for="(field,index) in formDef.fields">
      <!--栅格布局-->
      <ibps-dynamic-form-grid
        v-if="field.field_type === 'grid' || field.field_type === 'tabs' ||field.field_type === 'steps' || field.field_type === 'collapse'"
        :key="field.name+index"
        ref="formItem"
        :models.sync="models"
        :rights.sync="rights"
        :field="field"
        :code="code"
        :form-opinion="responseFormOpinionData[field.name]"
        :desc-position="formDef.attrs.descPosition"

        :params="formParams"
        :readonly-rights="readonlyRights"
        @change-form-opinion="handleFormOpinion"
      />
      <ibps-dynamic-form-item
        v-else
        ref="formItem"
        :key="field.name+index"
        :models.sync="models"
        :rights.sync="rights"
        :field="field"
        :code="code"
        :form-opinion="responseFormOpinionData[field.name]"
        :desc-position="formDef.attrs.descPosition"

        :params="formParams"
        :readonly-rights="readonlyRights"
        @change-form-opinion="handleFormOpinion"
      />
    </template>
  </van-form>
</template>

<script>

import FormOptions from '../constants/formOptions'
import FormUtils from '../utils/formUtil'

export default {
  provide() {
    return {
      dynamicForm: this
    }
  },
  props: {
    formDef: {
      type: Object,
      required: true
    },
    value: {
      type: Object
    },
    readonly: {
      type: Boolean,
      default: false
    },
    permissions: {
      type: Object
    },
    columnMinWidth: {
      type: String
    },
    validateImmediately: { // 是否初始验证
      type: Boolean,
      default: true
    },
    initialization: {
      type: Boolean,
      default: false
    },
    // 扩展参数
    params: Object,
    // 当前激活步骤
    curActiveStep: Number
  },
  data() {
    return {
      models: {}, // 表单model对象数据
      rights: {}, // 表单权限
      responseFormOpinionData: {},
      responseFormula: {}, // 公式
      responseLinkages: {},
      responseVerifys: [], // 表单提交校验
      responseOpinionFields: {}, // 表单的意见字段
      responseLabelFields: {}, // 表单的文本字段
      border: false,
      init: false,
      tabs: 'tabs_0',
      steps: 'steps_0'
    }
  },
  computed: {
    formAttrs() {
      return this.formDef ? this.formDef.attrs || {} : {}
    },
    colon() {
      return !!(this.formAttrs && this.formAttrs.colon)
    },
    labelWidth() {
      if (this.$utils.isNotEmpty(this.formAttrs.labelWidth) && this.$utils.isNotEmpty(this.formAttrs.labelWidthUnit)) {
        return this.formAttrs.labelWidth + this.formAttrs.labelWidthUnit
      } else {
        return '100px'
      }
    },
    labelPosition() {
      return this.$utils.isNotEmpty(this.formAttrs.mobileLabelPosition) ? this.formAttrs.mobileLabelPosition : 'right'
    },
    inputAlign() {
      return this.$utils.isNotEmpty(this.formAttrs.mobileInputAlign) ? this.formAttrs.mobileInputAlign : 'left'
    },
    customClass() {
      return this.$utils.isNotEmpty(this.formAttrs.customClass) ? this.formAttrs.customClass : null
    },
    code() {
      return this.formDef.code
    },
    readonlyRights() {
      return this.readonly
    },
    readonlyStyle() {
      return this.formAttrs && this.formAttrs.read_style ? this.formAttrs.read_style : 'text'
    },
    hasScript() {
      return this.formAttrs ? this.$utils.isNotEmpty(this.formAttrs.mobile_script) : false
    },
    formParams() { // 扩展参数
      const params = {
        code: this.code,
        responseFormula: this.responseFormula,
        responseLinkages: this.responseLinkages,
        responseFormOpinionData: this.responseFormOpinionData,
        readonly: this.readonly,
        permissions: this.rights,
        inputAlign: this.inputAlign
      }

      return Object.assign(params, this.params)
    }
  },
  watch: {
    formDef: {
      handler(val) {
        this.initResponseFields()
      },
      deep: true,
      immediate: true
    },
    models: {
      handler(val) {
        // 延迟验证
        this.$nextTick(() => {
          this.getFormValidator().then(() => { }).catch(() => {})
        })
      },
      deep: true,
      immediate: true

    },
    initialization(val) {
      if (val && this.hasScript) {
        this.$emit('load-script')
      }
    }
  },
  mounted() {
    // 初始化脚本
    this.$nextTick(() => {
      if (this.validateImmediately) {
        this.getFormValidator().then(() => { }).catch(() => {})
      }
    })
  },
  methods: {
    /**
     * 初始化字段
     */
    async initResponseFields() {
      const fields = this.formDef.fields
      if (!fields) { return }
      await this.generateModles(fields)
      // 初始化运行公式计算
      await this.initRunCalFormula()
      // 初始化表单意见
      await this.initResponseOpinionData()
    },
    /**
     * 生成modles
     */
    async generateModles(fields) {
      for (let i = 0; i < fields.length; i++) {
        const field = fields[i]
        const fieldName = field.name
        const fieldType = field.field_type
        const fieldOptions = field.field_options

        if (FormOptions.t.NESTED_FIELD_TYPES.includes(fieldType)) { // 嵌套布局
          if (this.$utils.isNotEmpty(fieldOptions) && this.$utils.isNotEmpty(fieldOptions.columns)) {
            // 循环遍历所有字段
            fieldOptions.columns.forEach(item => {
              this.generateModles(item.fields)
            })
          }
        } else if (fieldType === 'table') { // 子表单
          const data = this.value ? this.value[fieldName] : []
          if (fieldOptions.mode === 'block') {
            if (this.$utils.isEmpty(data)) {
              this.$set(this.models, fieldName, [])
              const defaultValue = await FormUtils.getTableDefaultData(field)
              this.models[fieldName].push(JSON.parse(JSON.stringify(defaultValue)))
            } else {
              this.models[fieldName] = data || []
            }
          } else {
            this.models[fieldName] = data || []
          }
          // 初始化表单扩展参数
          this.initFormFieldParameter(field)
        } else if (fieldType === 'approval_opinion') { // 审批意见
          this.models[fieldName] = ''
          this.responseOpinionFields[fieldName] = field
          // ====== 初始化表单权限
          this.initFormApprovalOpinionRights(field)
        } else {
          if (fieldType === 'label') { // 文本字段
            this.responseLabelFields[fieldName] = field
          }
          // 不是只读字段
          if (!FormOptions.t.NON_MODEL_FIELD_TYPES.includes(fieldType)) {
            // 空值默认
            const defaultValueEmpty = this.$utils.toBoolean(fieldOptions.default_value_empty, true)
            if (this.value && Object.keys(this.value).indexOf(fieldName) >= 0) { // 有值
              const data = this.value[fieldName]
              if (this.$utils.isEmpty(data)) {
                if (defaultValueEmpty) {
                  this.models[fieldName] = await FormUtils.getFieldDefaultValue(field)
                }
              } else {
                this.models[fieldName] = await this.getInitData(field, data)
              }
            } else { // 默认值
              this.models[fieldName] = await FormUtils.getFieldDefaultValue(field)
            }
          }
          // 初始化表单扩展参数
          this.initFormFieldParameter(field)
        }
      }
    },
    async getInitData(field, data) {
      const fieldType = field.field_type
      const copyFlow = this.$utils.toBoolean(this.formParams ? this.formParams.copyFlow : false, false)
      if (fieldType === 'autoNumber' && copyFlow) { // 复制流程初始化数据
        return await FormUtils.getFieldDefaultValue(field)
      }
      return data
    },
    /**
     *  初始化表单扩展参数
     */
    initFormFieldParameter(field) {
      // ====== 初始化表单权限
      this.initFormRights(field)
      // ====== 初始化需要进行公式计算的字段
      this.initResponseFormula(field)
      // ======  初始化需要进行联动数据的字段
      this.initResponseLinkages(field)
    },
    initFormApprovalOpinionRights(field) {
      this.rights[field.name] = FormUtils.getDefaultApprovalOpinionRigths(field, this.params) || this.getPermissions(this.permissions, field) || FormUtils.getDefaultRigths(field)
    },
    /**
     *  初始化表单权限
     */
    initFormRights(field) {
      this.rights[field.name] = this.getPermissions(this.permissions, field) || FormUtils.getDefaultRigths(field)
    },
    // 获取权限
    getPermissions(permissions, field) {
      if (this.$utils.isEmpty(permissions)) { return }
      const fieldType = field.field_type
      const name = field.name
      let rightsValue = null
      const isNonInputField = FormOptions.t.NON_INPUT_FIELD_TYPES.includes(fieldType)
      let isSpecial = false
      if (isNonInputField && permissions.fields) { // 非输入字段
        rightsValue = permissions.fields[name] ? permissions.fields[name] : null
      } else if (fieldType === 'approval_opinion' && permissions.opinions) { // 意见 特殊处理
        rightsValue = permissions.opinions[name] ? permissions.opinions[name] : null
      } else if (fieldType === 'table' && permissions.tables) { // 子表
        isSpecial = true
        rightsValue = permissions.tables[name] ? permissions.tables[name] : null
      } else { // 字段
        rightsValue = permissions.fields[name] ? permissions.fields[name] : null
      }
      if (this.readonly && !isNonInputField && !isSpecial) { // 只读权限
        // 修复空权限默认值的bug
        if (this.$utils.isEmpty(rightsValue)) {
          rightsValue = FormUtils.getDefaultRigths(field)
        }
        rightsValue = rightsValue !== FormOptions.t.PERMISSIONS.HIDE ? FormOptions.t.PERMISSIONS.READ : rightsValue
      }
      return rightsValue
    },
    // 初始化需要进行公式计算的字段
    initResponseFormula(item) {
      FormUtils.setResponseFormula(this.responseFormula, item, this.code)
    },
    // 初始化运行公式计算
    initRunCalFormula() {
      // 不需要字段的进行公式计算 比如获取但其当前时间
      FormUtils.runCalFormula(this, this.responseFormula[FormUtils.NOT_NEED_FIELD], this.formDef.code)
    },
    // 初始化联动数据
    initResponseLinkages(item) {
      FormUtils.setResponseLinkages(this.responseLinkages, item, this.code)
    },
    // 初始化表单意见
    initResponseOpinionData() {
      this.responseFormOpinionData = {}
      const opinionData = this.params ? this.params.formOpinionData || {} : {}
      if (this.$utils.isEmpty(opinionData) || !this.hasFormOpinion()) {
        return
      }
      const hasBindNode = opinionData.hasBindNode
      const formOpinionConfig = opinionData.formOpinionConfig
      if (hasBindNode) { // 1、有流程节点绑定的流程意见
        const nodeData = opinionData.formOpinionNodeData
        for (const key in this.responseOpinionFields) {
          if (this.responseOpinionFields.hasOwnProperty(key)) {
            if (formOpinionConfig[key]) {
              this.responseFormOpinionData[key] = nodeData[key]
            } else {
              this.responseFormOpinionData[key] = opinionData.opinionList
            }
          }
        }
      } else {
        for (const key in this.responseOpinionFields) {
          if (this.responseOpinionFields.hasOwnProperty(key)) {
            this.responseFormOpinionData[key] = opinionData.opinionList
          }
        }
      }
    },
    handleInput(data) {
      // 这里没有上报event，直接就是value了
      this.models = data
    },
    handleFormOpinion(opinionData) {
      let data = ''
      // 如果有多个，取最后一个
      if (this.$utils.isNotEmpty(opinionData)) {
        for (const o in opinionData) {
          data = opinionData[o] || ''
        }
      }
      this.opinionData = data
    },
    /**
     * 表单提交校验
     */
    formSubmitVerify(callback) {
      let flag = true
      const verifys = this.formAttrs ? this.formAttrs.verifys : []
      if (this.$utils.isEmpty(verifys)) {
        callback(flag)
        return
      }
      const formData = this.getFormData()
      for (let i = 0; i < verifys.length; i++) {
        const verify = verifys[i]
        if (!FormUtils.runFormSubmitVerify(verify.formula, formData, this.formDef.code)) {
          flag = false
          callback(flag, verify.msg)
          return
        }
      }
      flag = true
      callback(flag)
    },
    /**
     * 获取表单数据
     */
    getFormData() {
      const data = {}
      // 去除文本字段,表单意见字段
      for (var key in this.models) {
        if (!this.responseOpinionFields[key] && !this.responseLabelFields[key]) {
          data[key] = this.models[key]
        }
      }
      return data
    },
    /**
     * 设置表单字段数据
     */
    setFieldData(name, value) {
      this.models[name] = value
    },
    /**
     * 设置表单权限
     */
    setFormRights(name, value) {
      this.rights[name] = value
    },
    /**
     *  是否有审批意见字段
     */
    hasFormOpinion() {
      return this.$utils.isNotEmpty(this.responseOpinionFields)
    },
    /**
     * 获取审批意见数据
     */
    getFormOpinionData() {
      const data = {}
      for (var key in this.models) {
        if (this.responseOpinionFields[key] &&
        (this.$utils.isEmpty(this.rights[key]) || this.rights[key] === (FormOptions.t.PERMISSIONS.EDIT || FormOptions.t.PERMISSIONS.REQUIRED))
        ) {
          data[key] = this.models[key]
        }
      }
      return data
    },
    /**
     * 获取审批意见验证
     */
    formOpinionValidate(callback, flag = false) {
      if (this.$utils.isEmpty(this.responseOpinionFields)) {
        callback(true)
        return
      }
      let i = 0
      if (flag) {
        for (const key in this.responseOpinionFields) {
          if (this.$utils.isEmpty(this.models[key]) && (
            this.$utils.isEmpty(this.rights[key]) ||
            this.rights[key] === FormOptions.t.PERMISSIONS.EDIT ||
            this.rights[key] === FormOptions.t.PERMISSIONS.REQUIRED)) {
            i++
          }
        }
      } else {
        for (const key in this.responseOpinionFields) {
          if (this.$utils.isEmpty(this.models[key]) && this.rights[key] === FormOptions.t.PERMISSIONS.REQUIRED) {
            i++
          }
        }
      }

      if (i > 0) {
        callback(false)
      } else {
        callback(true)
      }
    },
    /**
     * 表单验证
     */
    getFormValidator() {
      this.$refs.form.resetValidation()
      return this.$refs.form.validate()
    },
    /**
     * 表单验证错误信息
     */
    scrollToField(name) {
      return this.$refs.form.scrollToField(name)
    }
  }
}
</script>

