<template>
  <a-card v-if="config" :bordered="false" :body-style="bodyStyle">
    <a-tabs
      :tabBarGutter="tabBarGutter"
      :activeKey="activeKey"
      @change="(activeKey) => tabPaneChange(activeKey, false)"
      :hideAdd="true"
      :animated="false"
      :tabBarStyle="{ display: showTabBar ? 'block' : 'none' }"
    >
      <template #tabBarExtraContent v-if="$slots.tabBarExtraContent || tabBarExtraContent">
        <slot name="tabBarExtraContent"></slot>
      </template>
      <slot name="extraBeforeTabs"></slot>
      <a-tab-pane
        v-for="(tab, index) in config.data"
        :key="index"
        :tab="tab.title"
        :forceRender="isTabLoaded(index)"
      >
        <component
          v-if="isTabLoaded(index)"
          :is="tab.slotType"
          :key="'xTabPaneComp' + index"
          :ref="`tab_com_${tab.slotType}_${index}`"
          :serviceName="tab.serviceName"
          :serverName="tab.serviceName"
          :queryParamsName="tab.slotConfig"
          v-on="getEventHandlers(tab,index)"
          @hook:mounted="(h)=>onComponentMounted(h,tab,index)"
          :config-name="tab.slotConfig"
          :slot-ref="tab.slotRef"
          :env="env"
          v-bind="compProp"
          :extra-data="extraData"
        />
      </a-tab-pane>
    </a-tabs>
  </a-card>
</template>

<script>
import { getConfigByName, getConfigByNameAsync, runLogic } from '@vue2-client/services/api/common'
import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
import { getRealKeyData } from '@vue2-client/utils/util'
import { getMicroData, getWindow, isMicroAppEnv, microDispatch } from '@vue2-client/utils/microAppUtils'
import { mapState } from 'vuex'
import { shortcutManager } from '@vue2-client/base-client/utils/shortcutManager'

export default {
  name: 'XTab',
  components: {
    XFormTable: () => import('@vue2-client/base-client/components/common/XFormTable/XFormTable'),
    XAddNativeForm: () => import('@vue2-client/base-client/components/common/XAddNativeForm/XAddNativeForm.vue'),
    XReportGrid: () => import('@vue2-client/base-client/components/common/XReportGrid/XReport.vue')
  },
  inject: {
    isInAModal: { default: false },
    getSelectedId: { default: false },
    getSelectedData: { default: false },
    getOutEnv: { default: false },
    setGlobalData: { default: false },
    getGlobalData: { default: false },
    generalFunction: { default: false },
    registerComponent: { default: false },
    getGridScopePath: { default: null }
  },
  provide () {
    return {
      currUser: this.currUser,
      getSelectedId: this.getSelectedId,
      // 暴露页签加载相关方法，供子组件调用
      ensureTabLoaded: this.ensureTabLoaded,
      getTabComponent: this.getTabComponent,
      isTabLoaded: this.isTabLoaded,
      getGridScopePath: () => this.myFullScopePath
    }
  },
  created () {
    this.myRoutePath = this.$route?.path || 'default'
    let parentPath = ''
    if (typeof this.getGridScopePath === 'function') {
      parentPath = this.getGridScopePath()
    }
    const tabConfig = this.getSlotConfig()
    this.myFullScopePath = parentPath ? `${parentPath}/${tabConfig}` : tabConfig
  },
  data () {
    return {
      activeKey: -1,
      // 配置
      config: undefined,
      tabBarExtraContent: undefined,
      attr: {},
      showTabBar: true, // 默认显示页签
      loadedTabs: [], // 记录已加载的页签索引
      myRoutePath: undefined,
      myFullScopePath: ''
    }
  },
  computed: {
    ...mapState('account', { currUser: 'user' })
  },
  mounted () {
    const savedKey = this.tryGetSavedKey()
    if (savedKey !== null) {
      this.tabPaneChange(savedKey, true)
    } else {
      this.tabPaneChange(this.activeKey !== -1 ? this.activeKey : this.defaultActiveKey, true)
    }
  },
  activated () {
    const savedKey = this.tryGetSavedKey()
    if (savedKey !== null && savedKey !== undefined) {
      this.tabPaneChange(savedKey, true)
    }
  },
  deactivated () {
    if (this.activeKey >= 0) {
      shortcutManager.saveRouteActiveKey(this.myRoutePath, this.activeKey, this.getOwnScopePath())
    }
  },
  methods: {
    // 自定义函数中调用的方法  这个不能删
    getWindow,
    runLogic,
    isMicroAppEnv,
    microDispatch,
    getMicroData,
    getRealKeyData,
    getConfigByName,
    getConfigByNameAsync,
    async tabPaneChange (newKey, initStatus = false) {
      if (this.activeKey >= 0 && this.activeKey !== newKey) {
        this.markTabAsLoaded(this.activeKey)
      }
      if (initStatus) {
        const routePath = this.$route?.path || 'default'
        const snapshot = shortcutManager.routeStateSnapshots.get(routePath)
        console.log('[tabPaneChange] initStatus:', initStatus, 'newKey:', newKey, 'routePath:', this.$route?.path)
        console.log('[tabPaneChange] snapshot:', snapshot)
        // 有快照就恢复作用域，然后清空 tabStates（保留 tabActiveKeys）
        if (snapshot?.tabStates?.size > 0) {
          snapshot.tabStates.forEach((wasActive, scopeId) => {
            shortcutManager.scopeActive.set(scopeId, wasActive)
          })
          snapshot.tabStates.clear()
        }

        // 有保存的 activeKey 就跳过
        if (this.tryGetSavedKey() != null) return
      }

      let result = {}
      if (this.activeKey === newKey) {
        return
      }

      const oldKey = this.activeKey

      // 标记新页签为已加载
      if (this.config && this.config.data && this.config.data[newKey] !== undefined) {
        this.markTabAsLoaded(newKey)
      }

      if (this.config && this.config.changeFunc && this.config.data[newKey] !== undefined) {
        let oldRef
        let oldTabName
        let newRef
        let newTabName

        if (!this.config.data[oldKey]) {
          oldTabName = `tab_com_${oldKey}`
          oldRef = this.$refs[oldTabName]
        } else {
          const oldTabSlotType = this.config.data[oldKey].slotType
          oldTabName = `tab_com_${oldTabSlotType}_${oldKey}`
          oldRef = this.$refs[oldTabName]
        }

        if (!this.config.data[newKey]) {
          newTabName = `tab_com_${newKey}`
          newRef = this.$refs[newTabName]
        } else {
          const newTabSlotType = this.config.data[newKey].slotType
          newTabName = `tab_com_${newTabSlotType}_${newKey}`
          newRef = this.$refs[newTabName]
        }

        const args = [
          oldKey,
          newKey,
          this.config.data[oldKey],
          this.config.data[newKey],
          oldRef ? oldRef[0] : undefined,
        ]
        args.push(newTabName)

        // 关键修改：确保新组件实例存在
        if (!newRef || !newRef[0]) {
          // 等待组件挂载完成
          await this.waitForComponentReady(newKey)
          newRef = this.$refs[newTabName]
        }

        if (newRef && newRef[0]) {
          args.push(newRef[0])
        } else {
          args.push(null)
          console.error('新页签组件实例获取失败')
        }

        args.push(this.extraData)

        // 使用 $nextTick 确保 DOM 更新完成
        await this.$nextTick()

        // 确保组件完全就绪后再执行 changeFunc
        if (newRef && newRef[0]) {
          // 等待组件完全就绪（包括内部异步初始化）
          await this.waitForComponentFullyReady(newRef[0], newKey)
        } else {
          // 如果没有组件实例，等待一个 tick 确保 DOM 更新
          await this.$nextTick()
        }

        result = executeStrFunctionByContext(this, this.config.changeFunc, args)

        if (result && result.noChange) {
          console.info('不切换页签作为按钮使用')
          // 如果返回 noChange，恢复原来的 activeKey
          if (this.activeKey === newKey) {
            this.activeKey = oldKey
          }
        } else {
          // 确保 activeKey 已更新（如果还没更新的话）
          if (this.activeKey !== newKey) {
            this.activeKey = newKey
          }
          // 确保回调在组件完全就绪后执行
          if (result && result.callback && typeof result.callback === 'function') {
            await this.$nextTick()
            result.callback()
          }
        }
      } else {
        this.activeKey = newKey
      }

      if (initStatus) {
        this.initShortcutTabScope()
      }

      // 每次切换后，重新应用单个页签的显示/隐藏规则
      this.applyTabHeaderVisibility()

      if (!initStatus && oldKey !== undefined && oldKey !== -1 && oldKey !== newKey) {
        this.switchShortcutTabScope(oldKey, newKey)
      }
    },
    applyTabHeaderVisibility () {
      // 根级 showTabBar 为 false 时，整个头都不显示，就不再处理单个页签
      if (!this.showTabBar || !this.config || !Array.isArray(this.config.data)) return

      this.$nextTick(() => {
        try {
          const navTabs = this.$el.querySelectorAll('.ant-tabs-nav .ant-tabs-tab')
          if (!navTabs || !navTabs.length) return

          this.config.data.forEach((tab, index) => {
            const tabNode = navTabs[index]
            if (!tabNode) return
            if (tab && tab.showTabBar === false) {
              tabNode.style.display = 'none'
            } else {
              tabNode.style.display = ''
            }
          })
        } catch (e) {
          // DOM 结构异常时不影响主流程
          console.error('applyTabHeaderVisibility error', e)
        }
      })
    },

    // 新增：等待组件就绪的方法
    waitForComponentReady (index) {
      return new Promise((resolve) => {
        const checkComponent = () => {
          const tab = this.config.data[index]
          const refName = `tab_com_${tab.slotType}_${index}`
          const ref = this.$refs[refName]

          if (ref && ref[0]) {
            // 额外检查组件内部是否已初始化（如果有相关状态的话）
            if (ref[0].isReady !== undefined) {
              if (ref[0].isReady) {
                resolve(ref[0])
              } else {
                setTimeout(checkComponent, 50)
              }
            } else {
              resolve(ref[0])
            }
          } else {
            setTimeout(checkComponent, 50)
          }
        }

        checkComponent()
      })
    },
    // 等待组件完全就绪（包括内部异步初始化）
    waitForComponentFullyReady (component, index) {
      return new Promise((resolve) => {
        if (!component) {
          resolve()
          return
        }

        let attempts = 0
        const maxAttempts = 60 // 最多等待3秒
        const checkInterval = 50

        const checkReady = () => {
          attempts++
          // 1. 检查组件是否有 loading 状态，确保不在加载中
          if (component.loading === true) {
            if (attempts < maxAttempts) {
              setTimeout(checkReady, checkInterval)
              return
            }
          }

          // 2. 检查组件是否有 loaded 状态（如 XAddNativeForm）
          if (component.loaded === false) {
            if (attempts < maxAttempts) {
              setTimeout(checkReady, checkInterval)
              return
            }
          }

          // 3. 检查组件是否有 realQueryConfig（如 XFormTable）
          const tab = this.config.data[index]
          const isFormTableType = tab?.slotType === 'x-form-table' ||
            tab?.slotType === 'XFormTable' ||
            tab?.slotType?.toLowerCase() === 'xformtable'
          if (isFormTableType && component.realQueryConfig === undefined && !component.loadError) {
            if (attempts < maxAttempts) {
              setTimeout(checkReady, checkInterval)
              return
            }
          }

          // 4. 检查关键方法是否存在（如 setForm、setFormWithKey）
          const hasSetForm = typeof component.setForm === 'function'
          const hasSetFormWithKey = typeof component.setFormWithKey === 'function'
          const hasSetFormWithNoKey = typeof component.setFormWithNoKey === 'function'
          // 5. 如果组件有这些方法，确保表单对象存在
          if (hasSetForm || hasSetFormWithKey || hasSetFormWithNoKey) {
            // 检查组件是否有 form 对象
            if (component.form && Object.keys(component.form).length > 0) {
              // 表单已初始化，等待 DOM 渲染完成
              this.$nextTick(() => {
                // 额外等待一个 tick，确保所有子组件也渲染完成
                this.$nextTick(() => {
                  resolve()
                })
              })
              return
            } else if (component.loaded !== false) {
              // 如果没有 form 对象但 loaded 不为 false，可能还在初始化
              if (attempts < maxAttempts) {
                setTimeout(checkReady, checkInterval)
                return
              }
            }
          }

          // 6. 如果以上都通过，或者超时，等待 DOM 渲染完成
          if (attempts >= 3 || attempts >= maxAttempts) {
            // 至少等待几次检查，确保有时间初始化
            this.$nextTick(() => {
              this.$nextTick(() => {
                resolve()
              })
            })
            return
          }

          // 继续等待
          setTimeout(checkReady, checkInterval)
        }

        // 首次检查前等待一个 tick
        this.$nextTick(() => {
          checkReady()
        })
      })
    },
    initConfig () {
      if (this.configName) {
        this.getConfig()
      } else if (this.localConfig) {
        this.config = this.localConfig
        // 设置是否显示页签
        this.showTabBar = this.localConfig.showTabBar !== false
      }
      // 重置已加载页签集合，确保配置变更后重新加载
      this.loadedTabs = []
      // 初始化完成后，根据每个 tab 的 showTabBar 设置头部显示
      this.applyTabHeaderVisibility()
    },
    getConfig () {
      getConfigByName(this.configName, this.serverName, res => {
        this.config = res
        // 设置是否显示页签
        this.showTabBar = res.showTabBar !== false
        // 从服务端配置加载完成后，应用单个页签的显示/隐藏
        this.applyTabHeaderVisibility()
      }, this.env === 'dev')
    },
    getEventHandlers (tab, index) {
      const handlers = {}
      if (!tab?.events || tab?.events?.length === 0) {
        return handlers
      }
      tab.events.forEach(event => {
        handlers[event.type] = (...args) => {
          executeStrFunctionByContext(this.$refs[`tab_com_${tab.slotType}_${index}`][0], event.customFunction, args)
        }
      })
      return handlers
    },
    onComponentMounted (h, tab, index) {
      // 与 Cover 普通子组件一致：带 slotRef 的 pane 由父级（XTab）注册到当前 Cover
      if (tab.slotRef && this.registerComponent) {
        const paneRef = this.$refs[`tab_com_${tab.slotType}_${index}`]
        const component = Array.isArray(paneRef) ? paneRef[0] : paneRef
        if (component) {
          this.registerComponent(tab.slotRef, component)
        }
      }
      if (tab.slotType === 'x-add-native-form') {
        // 建议表单需要主动调用初始化方法
        getConfigByName(tab.slotConfig, tab.serviceName, async (res) => {
          // 如果配置了 表单初始化logic
          // 调用 logic 获取参数
          let param = {}
          let selectedId
          if (res.paramLogicName) {
            if (!!this.getSelectedId) {
              selectedId = this.getSelectedId()
              if (typeof selectedId !== 'object') {
                selectedId = { selectedId: selectedId }
              }
            }
            param = Object.assign(param, await runLogic(res.paramLogicName, selectedId, tab.serviceName))
          }
          this.$refs[`tab_com_${tab.slotType}_${index}`][0].init({
            formItems: res.formJson,
            showSubmitBtn: !this.isInAModal,
            businessType: '新增',
            layout: res.xAddFormLayout,
            ...res,
            fixedAddForm: param,
            modifyModelData: {
              files: param.files,
              images: param.images
            }
          })
        }, this.env === 'dev')
      }
    },
    // 判断页签是否已加载
    isTabLoaded (index) {
      const numIndex = Number(index)
      return this.loadedTabs.includes(numIndex) || Number(this.activeKey) === numIndex
    },
    // 标记页签为已加载
    markTabAsLoaded (index) {
      const numIndex = Number(index)
      // 确保是有效的数字索引，且未添加过
      if (!isNaN(numIndex) && numIndex >= 0 && !this.loadedTabs.includes(numIndex)) {
        this.loadedTabs.push(numIndex)
      }
    },
    // 确保页签已加载，如果未加载则先加载，返回 Promise 等待组件渲染完成
    ensureTabLoaded (index, options = {}) {
      return new Promise((resolve, reject) => {
        const numIndex = Number(index)
        const innerRefs = Array.isArray(options.innerRefs) ? options.innerRefs : []
        const allowSwitch = options.allowSwitch !== false
        // 验证索引有效性
        if (isNaN(numIndex) || numIndex < 0) {
          reject(new Error(`无效的页签索引: ${index}`))
          return
        }
        if (!this.config || !this.config.data || !this.config.data[numIndex]) {
          reject(new Error(`页签索引 ${index} 不存在`))
          return
        }
        // 如果已经加载，直接返回组件实例
        if (this.isTabLoaded(numIndex)) {
          const component = this.getTabComponent(numIndex)
          if (component) {
            if (innerRefs.length === 0) {
              resolve(component)
            } else {
              this.waitForInnerRefs(component, innerRefs, resolve, reject)
            }
          } else {
            // 已标记但组件可能还在渲染中，等待一下
            this.$nextTick(() => {
              const comp = this.getTabComponent(numIndex)
              if (comp) {
                if (innerRefs.length === 0) {
                  resolve(comp)
                } else {
                  this.waitForInnerRefs(comp, innerRefs, resolve, reject)
                }
              } else {
                // 等待组件mounted
                this.waitForComponent(numIndex, (c) => {
                  if (innerRefs.length === 0) {
                    resolve(c)
                  } else {
                    this.waitForInnerRefs(c, innerRefs, resolve, reject)
                  }
                }, reject)
              }
            })
          }
          return
        }
        // 标记为已加载，触发渲染
        this.markTabAsLoaded(numIndex)
        // 优先尝试在不切换页签的情况下获取组件
        this.$nextTick(() => {
          const comp = this.getTabComponent(numIndex)
          if (comp) {
            if (innerRefs.length === 0) resolve(comp)
            else this.waitForInnerRefs(comp, innerRefs, resolve, reject)
            return
          }
          // 若仍未渲染，且允许临时切换，则进行一次激活-恢复回退
          if (!allowSwitch) {
            // 不允许切换则进入常规等待（可能更慢）
            this.waitForComponent(numIndex, (c) => {
              if (innerRefs.length === 0) resolve(c)
              else this.waitForInnerRefs(c, innerRefs, resolve, reject)
            }, reject)
            return
          }
          const prevActive = this.activeKey
          this.activeKey = numIndex
          this.$nextTick(() => {
            this.waitForComponent(numIndex, (c) => {
              // 组件到位后再恢复原激活页签
              if (prevActive !== numIndex) {
                this.$nextTick(() => { this.activeKey = prevActive })
              }
              if (innerRefs.length === 0) resolve(c)
              else this.waitForInnerRefs(c, innerRefs, resolve, reject)
            }, reject)
          })
        })
      })
    },
    // 等待组件渲染完成
    waitForComponent (index, resolve, reject) {
      const maxAttempts = 50 // 最多尝试50次
      let attempts = 0
      const checkInterval = 50 // 每50ms检查一次
      const tab = this.config.data[index]
      const refName = `tab_com_${tab.slotType}_${index}`
      const checkComponent = () => {
        attempts++
        const component = this.$refs[refName]
        if (component && component[0]) {
          resolve(component[0])
          return
        }
        if (attempts >= maxAttempts) {
          reject(new Error(`等待页签 ${index} 组件加载超时`))
          return
        }
        setTimeout(checkComponent, checkInterval)
      }
      // 首次检查
      this.$nextTick(() => {
        checkComponent()
      })
    },
    // 等待内部 $refs 就绪
    waitForInnerRefs (component, innerRefs, resolve, reject) {
      const maxAttempts = 50
      let attempts = 0
      const checkInterval = 50
      const allReady = () => innerRefs.every(name => component.$refs && component.$refs[name])
      const check = () => {
        attempts++
        if (allReady()) {
          resolve(component)
          return
        }
        if (attempts >= maxAttempts) {
          reject(new Error(`等待内部 refs [${innerRefs.join(', ')}] 就绪超时`))
          return
        }
        setTimeout(check, checkInterval)
      }
      this.$nextTick(() => check())
    },
    // 获取页签的组件实例
    getTabComponent (index) {
      const numIndex = Number(index)
      if (isNaN(numIndex) || numIndex < 0 || !this.config || !this.config.data || !this.config.data[numIndex]) {
        return null
      }
      const tab = this.config.data[numIndex]
      const refName = `tab_com_${tab.slotType}_${numIndex}`
      const ref = this.$refs[refName]
      return ref && ref[0] ? ref[0] : null
    },

    // ========== 作用域管理 ==========
    buildFullTabPath (tabKey) {
      return `${this.myFullScopePath}/${tabKey}`
    },
    switchShortcutTabScope(oldKey, newKey) {
      if (!shortcutManager.isEnabled) return
      const prefix = `${this.$route?.path || 'default'}::${this.myFullScopePath}`

      // 使用独立快照 key，避免与路由快照冲突
      const routePath = this.$route?.path || 'default'
      const snapshotKey = `tab:${routePath}::${this.myFullScopePath}`

      let snapshot = shortcutManager.routeStateSnapshots.get(snapshotKey)
      if (!snapshot) {
        snapshot = {
          tabStates: new Map(),
          tabActiveKeys: {},
          lastAccess: Date.now()
        }
        shortcutManager.routeStateSnapshots.set(snapshotKey, snapshot)
      }

      // 1. 停用旧 Tab 并保存所有子作用域状态
      if (oldKey >= 0 && oldKey !== newKey) {
        const oldTab = this.config?.data?.[oldKey]
        if (oldTab) {
          const oldTabKey = oldTab.slotConfig || oldTab.title || String(oldKey)
          const oldPrefix = `${prefix}/${oldTabKey}`

          const scopesToSave = []
          shortcutManager.scopeActive.forEach((active, scopeId) => {
            if (scopeId.startsWith(oldPrefix)) {
              scopesToSave.push({ scopeId, active })
              shortcutManager.setScopeActive(scopeId, false)
            }
          })
          scopesToSave.forEach(({ scopeId, active }) => {
            snapshot.tabStates.set(scopeId, active)
          })
        }
      }

      // 2. 激活新 Tab 并从快照恢复所有子作用域
      const newTab = this.config?.data?.[newKey]
      if (newTab && newKey >= 0) {
        const newTabKey = newTab.slotConfig || newTab.title || String(newKey)
        const newPrefix = `${prefix}/${newTabKey}`

        shortcutManager.setScopeActive(newPrefix, true)

        if (snapshot.tabStates && snapshot.tabStates.size > 0) {
          snapshot.tabStates.forEach((wasActive, scopeId) => {
            if (scopeId.startsWith(newPrefix + '/') && wasActive) {
              shortcutManager.setScopeActive(scopeId, true)
            }
          })
        }

        snapshot.tabStates.set(newPrefix, true)
        snapshot.lastAccess = Date.now()
      }
    },
    initShortcutTabScope () {
      console.log('[initShortcutTabScope] myFullScopePath:', this.myFullScopePath, 'activeKey:', this.activeKey)
      if (!shortcutManager.isEnabled) return
      if (this.activeKey === -1 || !this.config?.data) return

      const prefix = `${this.$route?.path || 'default'}::${this.myFullScopePath}/`

      // 先停用该 XTab 下所有已激活的作用域
      shortcutManager.scopeActive.forEach((active, scopeId) => {
        if (active && scopeId.startsWith(prefix)) {
          shortcutManager.setScopeActive(scopeId, false)
        }
      })

      // 再激活当前 Tab
      const tabKey = this.getActiveTabKey()
      if (tabKey) {
        shortcutManager.setScopeActive(`${this.$route?.path || 'default'}::${tabKey}`, true)
      }
    },
    getActiveTabKey () {
      const key = this.activeTabKey ?? this.activeKey
      if (key < 0 || !this.config?.data) return null
      const activeTab = this.config.data[key]
      if (!activeTab) return null
      return `${this.myFullScopePath}/${activeTab.slotConfig || activeTab.title || String(key)}`
    },
    getSlotConfig () {
      return this.configName || this.$attrs['config-name'] || this.queryParamsName || ''
    },
    getOwnScopePath () {
      return this.myFullScopePath
    },

    // ========== 备份恢复 ==========
    tryGetSavedKey () {
      const saved = shortcutManager.getRouteActiveKey(this.$route?.path || 'default', this.getOwnScopePath())
      return saved ?? null
    }
  },
  props: {
    // 配置名
    configName: {
      type: String,
      default: undefined
    },
    serverName: {
      type: String,
      default: undefined
    },
    env: {
      type: String,
      default: 'prod'
    },
    // 本地配置，调试用
    localConfig: {
      type: Object,
      default: undefined
    },
    tabBarGutter: {
      type: Number,
      default: 10
    },
    bodyStyle: {
      type: Object,
      default: () => {
        return {}
      }
    },
    defaultActiveKey: {
      type: [String, Number],
      default: 0
    },
    // 新增compProp参数，用于穿透到动态组件
    compProp: {
      type: Object,
      default: () => {
        return {}
      }
    },
    // 额外数据
    extraData: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  watch: {
    configName: {
      deep: true,
      immediate: true,
      handler (val) {
        this.initConfig()
      }
    },
    // 如果本地配置更改了，重新初始化
    localConfig: {
      deep: true,
      immediate: true,
      handler (val) {
        this.initConfig()
      }
    },
  },
}
</script>
<style scoped>
/* 禁用所有 tabs 切换动画 */
:deep(.ant-tabs) {
  transition: none !important;
}
:deep(.ant-tabs-nav) {
  transition: none !important;
  transform: none !important;
}
:deep(.ant-tabs-tabpane) {
  transition: none !important;
}
:deep(.ant-tabs-tab) {
  transition: none !important;
}
:deep(.ant-tabs-ink-bar) {
  transition: none !important;
}
</style>
