<template>
  <div>
    <!--  骨架屏  -->
    <a-card v-if="showSkeleton">
      <a-skeleton active/>
    </a-card>
    <template v-if="noPadding">
      <!--   主体表格   -->
      <XReportDesign
        @updateImg="updateImg"
        v-if="scanFinish"
        :show-img-in-cell="showImgInCell"
        :img-prefix="imgPrefix"
        :use-oss-for-img="useOssForImg"
        :display-only="displayOnly"
        :config="type === 'display' ? originalConfig : activeConfig"
        :slot-config-name="type === 'display' ? undefined : activatedSlotName"
        :for-display="type === 'display'"
        ref="XReportDesign"
        id="printReady"
        :server-name="serverName"
        :show-title="showTitle"
        :no-padding="noPadding"
        :no-top-border="noTopBorder"
        :show-images="hasImages"
        :image-list="imageList">
      </XReportDesign>
    </template>
    <template v-else>
      <!--  用以包裹整个页面  -->
      <a-card v-if="!showSkeleton">
        <!--   切换菜单   -->
        <a-radio-group
          v-model="type"
          default-value="a"
          button-style="solid"
          @change="tabChanged"
          v-show="!onlyDisplay && editMode">
          <a-radio-button value="design" v-if="!onlyDisplay">
            设计
          </a-radio-button>
          <a-radio-button value="display" style="border-radius: 0">
            预览
          </a-radio-button>
        </a-radio-group>
        <a-radio-button @click="saveConfig" style="border-radius: 0 4px 4px 0" v-if="showSaveButton">
          保存
        </a-radio-button>
        <!--   主体表格   -->
        <XReportDesign
          v-if="scanFinish"
          @updateImg="updateImg"
          :show-img-in-cell="showImgInCell"
          :img-prefix="imgPrefix"
          :use-oss-for-img="useOssForImg"
          :display-only="displayOnly"
          :config="type === 'display' ? originalConfig : activeConfig"
          :slot-config-name="type === 'display' ? undefined : activatedSlotName"
          :for-display="type === 'display'"
          :no-padding="noPadding"
          :no-top-border="noTopBorder"
          :show-title="showTitle"
          ref="XReportDesign"
          id="printReady"
          :server-name="serverName"
          :show-images="hasImages"
          :image-list="imageList">
        </XReportDesign>
        <!--   导出按钮   -->
        <template v-if="type === 'display'">
          <div class="tools">
            <div class="toolsItem">
              <a-space>
                <a-button type="primary" @click="printDocument">
                  打印
                </a-button>
                <a-button @click="exportPDF">
                  导出PDF
                </a-button>
              </a-space>
            </div>
          </div>
        </template>
      </a-card>
    </template>
  </div>
</template>

<script>
// 转PDF用
import HtmlToPdf from '@vue2-client/utils/htmlToPDF'
import { getConfigByName } from '@vue2-client/services/api/common'
import XReportDesign from '@vue2-client/base-client/components/common/XReport/XReportDesign.vue'
import { printElement } from './print'

export default {
  name: 'XReport',
  props: {
    files: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 控制用户权限，user和admin
    authority: {
      type: String,
      default: 'user'
    },
    // 是否为编辑模式
    editMode: {
      type: Boolean,
      default: true
    },
    // 配置名
    configName: {
      type: String,
      required: true
    },
    // 插槽名
    activatedSlotName: {
      type: String,
      default: undefined
    },
    // 本地配置，调试用
    localConfig: {
      type: Object,
      default: undefined
    },
    // 兼容老版本配置
    dontFormat: {
      type: Boolean,
      default: true
    },
    showImgInCell: {
      type: Boolean,
      default: false
    },
    // 数据
    configData: {
      type: Object,
      default: undefined
    },
    // 命名空间
    serverName: {
      type: String,
      default: process.env.VUE_APP_SYSTEM_NAME
    },
    // 只做展示
    displayOnly: {
      type: Boolean,
      default: false
    },
    // 表格没有边距
    noPadding: {
      type: Boolean,
      default: false
    },
    // 表格没有上边框，与noPadding搭配可以实现连续表格
    noTopBorder: {
      type: Boolean,
      default: false
    },
    // 是否展示标题
    showTitle: {
      type: Boolean,
      default: true
    },
    // 是否展示保存按钮
    showSaveButton: {
      type: Boolean,
      default: true
    },
    // 是否将组件注册到外层提供的容器中，方便外侧统一保存
    registerMap: {
      type: Array,
      default: undefined
    },
    // 图片是否使用OSS来保存
    useOssForImg: {
      type: Boolean,
      default: true
    },
    // 图片上传后添加前缀
    imgPrefix: {
      type: String,
      default: undefined
    }
  },
  components: {
    XReportDesign
  },
  data () {
    return {
      // 控制骨架屏显隐
      showSkeleton: true,
      // 配置
      config: undefined,
      // 当前显示模式，编辑模式，预览模式
      type: 'design',
      // 仅供展示，不可编辑
      onlyDisplay: false,
      // 每行最大列数，非必要请勿更改，现在的设计器完全是基于每行12列来设计的
      maxColSpan: 12,
      // 定义是否完成配置的扫描，未完成不要渲染子组件
      scanFinish: false,
      // 当前激活的配置文件
      activeConfig: null,
      // 原始配置文件
      // 用于展示。某些情况下“设计页”中的内容仅为“预览页”表格其中的一部分
      originalConfig: null,
      // 扫描到的配置
      configFromWeb: {},
      // 用于获取配置的锁
      timer: undefined,
      // 是否包含图片
      hasImages: false,
      // 图片列表
      imageList: [],
      // 保存最原始的数据，用于判断哪些数据被更改了
      dataCache: undefined,
      // 判断哪些数据被更改了，存储对应的key
      diff: []
    }
  },
  watch: {
    // 如果配置名更改了，重新获取配置
    configName (val) {
      if (val) {
        getConfigByName(this.configName, undefined, res => {
          this.config = res
          this.configInit()
        })
      }
    },
    // 如果本地配置更改了，重新初始化
    localConfig (val) {
      if (val) {
        this.config = val
        this.configInit()
      }
    }
  },
  methods: {
    // 向外暴露图片修改后的数据，某些外部需要自己管理图片的保存与修改
    updateImg (data) {
      this.$emit('updateImg', data)
    },
    // 导出数据，某些外部需要统一控制数据的变动
    exportData (skipValidation = false) {
      // 如果不跳过校验，先进行必填字段校验
      if (!skipValidation) {
        const validation = this.validateRequiredFields()
        if (!validation.isValid) {
          const errorMessages = validation.errors.map(error => error.message).join('；')
          console.warn(`数据导出警告：存在必填字段未填写 - ${errorMessages}`)
          // 在导出时只警告，不阻止导出
        }
      }

      // 获取当前修改后的数据
      let tempData
      if (this.activeConfig === undefined || this.activeConfig === null) {
        tempData = this.originalConfig.data
      } else {
        const tempDataKeys = Object.keys(this.activeConfig.tempData)
        tempDataKeys.forEach(key => {
          this.changeDeepObject(this.activeConfig.data, key, this.activeConfig.tempData[key])
        })
        tempData = this.activeConfig.data
      }
      // 对比数据的差异
      this.diff = []
      this.compareProps(tempData, this.dataCache)
      this.diff.forEach(eachDiff => {
        const arr = eachDiff.split('.')
        let targetData = tempData[arr[0]]
        if (arr.length !== 1) {
          for (let i = 1; i < arr.length - 1; i++) {
            const path = arr[i]
            targetData = targetData[path]
          }
        }
        // 将修改的数据，添加update = true属性
        targetData.update = true
      })
      return tempData
    },
    // 对比两个obj有哪里不同
    compareProps (obj1, obj2, path = '') {
      for (const key in obj1) {
        // 如果一个是undefined
        if (typeof obj2[key] === 'undefined') {
          this.diff.push(path + key)
          // 如果是数组长度不一样
        } else if (Array.isArray(obj1) && Array.isArray(obj2)) {
          if (obj1[key].length !== obj2[key].length) {
            this.diff.push(path + key)
          }
          // 如果都是对象，并且存在同样的key，递归子key
        } else if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
          this.compareProps(obj1[key], obj2[key], path + key + '.')
          // 如果不是obj，对比其数据
        } else if (obj1[key] !== obj2[key]) {
          this.diff.push(path + key)
        }
      }
    },
    // 验证必填字段
    validateRequiredFields () {
      const errors = []
      const config = this.type === 'display' ? this.originalConfig : this.activeConfig

      if (!config || !config.columns) {
        return { isValid: true, errors: [] }
      }

      // 遍历所有配置项检查必填字段
      config.columns.forEach((row, rowIndex) => {
        row.forEach((cell, cellIndex) => {
          if (cell.required && cell.dataIndex) {
            let value
            if (cell.dataIndex.indexOf('@@@') !== -1) {
              // 处理深层嵌套数据
              // const arr = cell.dataIndex.split('@@@')
              value = config.tempData && config.tempData[cell.dataIndex]
            } else {
              value = config.data[cell.dataIndex]
            }

            // 检查值是否为空
            if (!value || (typeof value === 'string' && value.trim() === '')) {
              const message = cell.requiredMessage || this.getDefaultRequiredMessage(cell.type)
              errors.push({
                dataIndex: cell.dataIndex,
                message: message,
                rowIndex: rowIndex,
                cellIndex: cellIndex,
                type: cell.type
              })
            }
          }
        })
      })

      return {
        isValid: errors.length === 0,
        errors: errors
      }
    },
    // 获取默认的必填提示信息
    getDefaultRequiredMessage (fieldType) {
      const defaultMessages = {
        datePicker: '请选择日期',
        timePicker: '请选择日期时间',
        input: '请填写此字段',
        inputs: '请填写此字段'
      }
      return defaultMessages[fieldType] || '此字段为必填项'
    },
    // 正常的保存方法，当前修改内容会直接全部导出到外部
    saveConfig () {
      // 先进行必填字段校验
      const validation = this.validateRequiredFields()
      if (!validation.isValid) {
        const errorMessages = validation.errors.map(error => error.message).join('；')
        this.$message.error(`保存失败：${errorMessages}`)
        return false
      }

      if (this.activeConfig === undefined || this.activeConfig === null) {
        return this.originalConfig.data
      } else {
        const tempDataKeys = Object.keys(this.activeConfig.tempData)
        tempDataKeys.forEach(key => {
          this.changeDeepObject(this.activeConfig.data, key, this.activeConfig.tempData[key])
        })
        this.$emit('saveConfig', this.$refs.XReportDesign.activatedConfig)
        return true
      }
    },
    // 通过@@@分割临时变量，找到对应的key，并修改它的值
    changeDeepObject (obj, strPath, newVal) {
      const arr = strPath.split('@@@')
      if (obj[arr[0]] === undefined) {
        obj = obj.images
      }
      if (arr.length === 1) {
        obj[arr[0]] = newVal
      } else {
        let result = obj[arr[0]]
        arr.shift()
        while (arr.length > 1) {
          result = result[arr[0]]
          arr.shift()
        }
        if (result) {
          result[arr[0]] = newVal
        }
      }
    },
    // 检查slot是否在配置文件中包含，如果没有包含，则视为非法获取
    checkSlotDefine (config) {
      const slotsDeclare = config.slotsDeclare
      const total = slotsDeclare.length
      let count = 0
      slotsDeclare.forEach(declare => {
        config.columns.forEach(row => {
          row.forEach(cell => {
            if (cell.slotConfig === declare) {
              count++
            }
          })
        })
      })

      return count === total
    },
    // 切换了标签页
    tabChanged (key) {
      this.scanFinish = false
      this.originalConfig.data = { ...this.originalConfig.data, ...this.config.data }
      this.config.data = this.originalConfig.data
      if (this.type === 'display') {
        const tempDataKeys = Object.keys(this.activeConfig.tempData)
        tempDataKeys.forEach(key => {
          this.changeDeepObject(this.activeConfig.data, key, this.activeConfig.tempData[key])
        })
        let count = 0
        this.imageList = []
        const keys = Object.keys(this.config.data.images)
        keys.forEach(key => {
          if (this.config.data.images[key].length > 0) {
            this.imageList = [...this.imageList, ...this.config.data.images[key]]
            count++
          }
        })
        this.hasImages = count > 0
      } else {
        this.hasImages = false
      }
      this.$nextTick(() => {
        this.scanFinish = true
      })
    },
    // 获取当前日期，为保存文件命名用
    getDate () {
      const currentDate = new Date()

      const year = currentDate.getFullYear()
      const month = String(currentDate.getMonth() + 1).padStart(2, '0')
      const day = String(currentDate.getDate()).padStart(2, '0')

      const formattedDate = `${year}_${month}_${day}`

      return formattedDate
    },
    // 打印
    printDocument () {
      // x-report
      const printContent = window.rawDocument.getElementById('printReady')
      printElement(printContent)
      this.$message.success('操作成功！')
    },
    // 导出PDF
    exportPDF () {
      const date = this.getDate()
      let title = this.config.title
      title = title.replace(/<[^>]+>/g, '')
      const fileName = date + '' + title
      HtmlToPdf.getPdf(fileName, '#printReady')
    },
    // 用于分割配置中的colums，将需要处理的数组提取出来
    formatConfigRow () {
      for (let i = 0; i < this.config.columns.length; i++) {
        // 对原始数组进行递归，依次将该位置拆分为三个部分，当前处理位置之前的，当前处理位置，当前处理位置之后的
        const before = this.config.columns.slice(0, i)
        const after = this.config.columns.slice(i + 1, this.config.columns.length)

        // 将当前处理的数组交给处理的方法
        const x = this.checkRow(this.config.columns[i])

        const newArr = []

        // 拼接之前的数组
        if (before.length > 0) {
          if (before.length >= 1) {
            before.forEach(item => {
              newArr.push(item)
            })
          } else {
            newArr.push(before)
          }
        }

        // 拼接不需要更改当前节点处理完成的数组
        newArr.push(x.old)

        // 如果处理了新加的数据，拼接
        if (x.add.length > 0) {
          for (let j = 0; j < x.add.length; j++) {
            if (x.add[j]) {
              newArr.push(x.add[j])
              i++
            }
          }
        }

        // 拼接之后的数组
        if (after.length > 0) {
          if (after.length >= 1) {
            after.forEach(item => {
              newArr.push(item)
            })
          } else {
            newArr.push(after)
          }
        }

        this.config.columns = newArr
      }
    },
    // 路径中含有@@@的key，将其解析，并返回其数据
    getDeepObject (obj, strPath) {
      const arr = strPath.split('@@@')
      let result = obj[arr[0]]
      arr.shift()
      try {
        while (arr.length > 0) {
          result = result[arr[0]]
          arr.shift()
        }
      } catch (e) {
        result = undefined
      }
      return result
    },
    // 处理colums数组，为声明了rowspan的单元格，自动匹配格式
    checkRow (rowArr) {
      // 不需要更改的数据
      const original = []
      // 需要更改新加的数据
      const addArr = []
      // 统计rowspan出现的总和
      let count = 0
      // 统计声明列需要的rowspan总数
      let total = 0
      // 是否为声明行
      let titleCellFlag = false
      // 是否为声明行后第一行
      let firstSubLine = false
      // 需要处理的行，新的index值
      let subRowIndex = 0
      // 新生成的行，临时存储
      const waitForAddArr = []
      // 用于记录声明行的colspan避免格式错误
      let preColSpan = 0
      // 用于统计循环次数，判断是否是最后一次
      let forEachCount = 0

      // 标记所有数据
      rowArr.forEach(cell => {
        forEachCount++
        // 如果该行没有rowspan则默认其为1，不要影响统计结果
        if (!cell.rowSpan) {
          cell.rowSpan = 0
        }

        if (cell.text && total !== 0) { // 如果遇到了下一个声明行，证明rowspan少了一行，需要补充一个占位格
          const nullObj = {
            type: 'placeHolderColumn',
            order: subRowIndex,
            noBoarder: true,
            needSplit: true,
            colSpan: preColSpan,
            dontShowRow: true
          }
          subRowIndex++
          waitForAddArr.push(nullObj)
          total = 0
          count = 0
          titleCellFlag = false
          firstSubLine = false
        } else if ((total !== count + cell.rowSpan) && forEachCount === rowArr.length) {
          // 如果没有遇到了下一个声明行，但已经是当前行最后一个数据，也证明rowspan少了一行，需要补充一个占位格
          const nullObj = {
            type: 'placeHolderColumn',
            order: subRowIndex,
            noBoarder: true,
            needSplit: true,
            colSpan: preColSpan,
            dontShowRow: true
          }
          subRowIndex++
          waitForAddArr.push(nullObj)
          total = 0
          count = 0
          titleCellFlag = false
          firstSubLine = false
        }

        // 判断是否为声明行
        if (cell.text && total === 0) {
          // 将声明行声明的rowspan作为总数，判断下方rowspan相加是否等于声明行声明的数量
          total = cell.rowSpan
          titleCellFlag = false
          firstSubLine = true
          subRowIndex = 1
          cell.show = true
          cell.showRowSpan = total
        } else if (cell.rowSpan > 0 && !titleCellFlag && firstSubLine) { // 判断是否为声明行后首行，因为首行不需要移动
          count += cell.rowSpan
          firstSubLine = false
          cell.noBoarder = true
          cell.show = true
          cell.showRowSpan = total
        } else if (cell.rowSpan > 0 && !titleCellFlag && !firstSubLine) { // 既非声明行，也非首行，需要移动
          count += cell.rowSpan
          // cell.type = 'notShow'
          cell.needSplit = true
          cell.order = subRowIndex
          cell.dontShowRow = true
          subRowIndex++

          // 如果之前添加过空行补充位置，刚好最后一位还有内容，将其互换
          if (forEachCount === rowArr.length && !waitForAddArr[waitForAddArr.length - 1].dataIndex) {
            waitForAddArr[waitForAddArr.length - 1].order += 1
            cell.order -= 1
            waitForAddArr.push(cell)
          } else {
            waitForAddArr.push(cell)
          }
        }

        // 如果count和total相等了，证明已经处理完成。将计数器还原
        if (count === total) {
          total = 0
          count = 0
          titleCellFlag = false
          firstSubLine = false
        }
        // 保存上一个的colspan，保持生成的格子与原格式一致
        preColSpan = cell.colSpan
      })

      // 将所有不需要移动的放入original
      rowArr.forEach(cell => {
        if (cell.needSplit !== true) {
          original.push(cell)
        }
      })

      // 增加新的数组
      waitForAddArr.forEach(cell => {
        const target = cell.order
        // if (cell.type === 'notShow') {
        //   cell.type = 'inputs'
        // }
        cell.noBoarder = true
        if (addArr[target] === undefined) {
          const temp = []
          temp.push(cell)
          addArr[target] = temp
        } else if (addArr[target].length > 0) {
          addArr[target].push(cell)
        }
      })

      // 如果没有新增，将单元格边框设置为显示
      if (addArr.length < 1) {
        original.forEach(cell => {
          if (cell.type === 'input' || cell.type === 'inputs') {
            cell.noBoarder = false
          }
        })
      }

      return {
        old: original,
        add: addArr
      }
    },
    // 扫描配置，如果有插槽则拼接插槽
    scanConfigSlot (config) {
      const columnsArr = config.columns
      for (let i = 0; i < columnsArr.length; i++) {
        for (let j = 0; j < columnsArr[i].length; j++) {
          // 如果发现type为slot，开始匹配对应的slot配置文件
          if (columnsArr[i][j].type === 'slot') {
            const targetName = columnsArr[i][j].slotConfig
            // 找不到目标插槽配置
            if (!this.configFromWeb[targetName] || !this.configFromWeb[targetName].columns) {
              console.error('无法找到目标插槽的配置！')
              return
            }

            // 替换columns，合并data
            config.columns[i] = []
            const before = config.columns.slice(0, i)
            let after = config.columns.slice(i + 1, config.columns.length)

            const addArr = []
            for (let k = 0; k < this.configFromWeb[targetName].columns.length; k++) {
              const temp = []
              this.configFromWeb[targetName].columns[k].forEach(cell => {
                temp.push(cell)
              })
              addArr.push(temp)
            }

            const newArr = []
            // 拼接之前的数组
            if (before.length > 0) {
              if (before.length >= 1) {
                before.forEach(item => {
                  newArr.push(item)
                })
              } else {
                newArr.push(before)
              }
            }

            addArr.forEach(arr => {
              newArr.push(arr)
            })

            // 拼接之后的数组
            if (after.length === 1) {
              if (after[0].type === 'slot' || after[0][0].type === 'slot') {
                after = []
              }
            }
            if (after.length > 0) {
              if (after.length >= 1) {
                after.forEach(item => {
                  newArr.push(item)
                })
              } else {
                newArr.push(after)
              }
            }

            config.columns = newArr
            if (this.configFromWeb[targetName].slotsDeclare) {
              config.slotsDeclare = this.configFromWeb[targetName].slotsDeclare
            } else {
              config.slotsDeclare = []
            }

            if (config.data.images && this.configFromWeb[targetName].data.images) {
              config.data.images = { ...config.data.images, ...this.configFromWeb[targetName].data.images }
              delete this.configFromWeb[targetName].data.images
            }
            config.data = { ...config.data, ...this.configFromWeb[targetName].data }
          }
        }
      }
      this.config = config
    },
    // 扫描所有插槽名
    scanConfigName (config, resut) {
      if (config.slotsDeclare) {
        config.slotsDeclare.forEach(name => {
          resut.push(name)
        })
      }
    },
    // 获取插槽
    getConfigAndJoin (config, outerLock) {
      // 检查主配置插槽声明是否合法
      const check = this.checkSlotDefine(config)
      const waitForDownloadSlotName = []
      if (check) {
        // 扫描主配置中声明的插槽名
        this.scanConfigName(config, waitForDownloadSlotName)

        const total = waitForDownloadSlotName.length
        let count = 0

        // 挨个获取插槽
        waitForDownloadSlotName.forEach(configName => {
          getConfigByName(configName, this.serverName, res => {
            this.configFromWeb[configName] = res
            count++
          })
        })

        // 使用定时器循环判断锁状态，用于多个插槽，要等待统一获取完成之后，再进行下一步初始化
        const timer = setInterval(() => {
          console.log('插槽下载进度，当前：' + count + '/' + total)
          if (count >= total) {
            clearInterval(timer)
            this.scanConfigSlot(config)
            if (config.slotsDeclare.length > 0) {
              const lock = { status: true }
              this.getConfigAndJoin(config, lock)
              const innerTimer = setInterval(() => {
                if (!lock.status) {
                  clearInterval(innerTimer)
                  outerLock.status = false
                }
              }, 100)
            } else {
              outerLock.status = false
            }
          }
        }, 100)
      } else {
        console.error('插槽配置有误！')
        outerLock.status = false
      }
    },
    // 获取配置之后的初始化
    configInit () {
      // 上锁，等待所有配置获取完成
      const lock = { status: true }

      // 获取插槽
      this.getConfigAndJoin(this.config, lock)

      // 用定时器循环查看锁状态
      this.timer = setInterval(() => {
        if (!lock.status) {
          clearInterval(this.timer)
          console.log('拼接完成', this.config)
          // 将初始化好的配置拷贝一份留存
          this.originalConfig = Object.assign({}, this.config)
          if (!this.dontFormat) {
            // 扫描配置文件中有没有rowSpan，进行格式化调整
            this.formatConfigRow(this.config)
          }
          this.activeConfig = this.config
          this.showSkeleton = false
          // 判断是否有动态Index
          this.activeConfig.columns.forEach(row => {
            row.forEach(cell => {
              if (cell.dynamicDataIndex === true) {
                // 如果有动态index，取其函数，运行函数得到真实index保存
                // eslint-disable-next-line no-eval
                const func = eval('(' + cell.customFunctionForDynamicDataIndex + ')')
                cell.dataIndex = func(this.config)
              }
            })
          })
          // 将数据复制到临时数据中，带有@@@的数据，我们将其整体作为一个key保存，当编辑完成后，再将其解析，回填到需要的数据中
          this.activeConfig.tempData = {}
          // 是否有@@@深层引用
          this.activeConfig.columns.forEach(row => {
            row.forEach(cell => {
              // 将@@@解析
              if (cell.dataIndex !== undefined && cell.dataIndex.indexOf('@@@') !== -1) {
                this.activeConfig.tempData[cell.dataIndex] = this.getDeepObject(this.activeConfig.data, cell.dataIndex)
              }
            })
          })
          this.$nextTick(() => {
            this.scanFinish = true
          })
        }
      }, 100)
    },
    // 初始化JSON配置
    jsonConfigInit () {
      if (this.configData === undefined) {
        console.error('未找到数据！')
      } else {
        this.originalConfig = Object.assign({}, this.config)
        this.originalConfig.data = Object.assign(this.originalConfig.data, JSON.parse(JSON.stringify(this.configData)))
        this.type = 'display'
        // this.onlyDisplay = true
        this.showSkeleton = false
        this.$nextTick(() => {
          this.scanFinish = true
        })
      }
    },
    initByConfigName () {
      getConfigByName(this.configName, this.serverName, res => {
        this.config = res
        if (this.config.designMode === 'json') {
          if (this.configData !== undefined) {
            this.config.data = Object.assign({}, this.config.data, this.configData)
          }
          this.jsonConfigInit()
        } else {
          if (this.configData !== undefined) {
            this.config.data = Object.assign(this.config.data, this.configData)
          }
          if (this.config.data.images === undefined) {
            this.config.data.images = {}
          }
          this.configInit()
        }
      })
    },
    // 提供主动让外部调用的初始化方法
    async init ({ configName, configData }) {
      this.configName = configName
      this.configData = configData
      await this.initByConfigName()
    },
    // 提供主动赋值方法
    setData (data) {
      this.config.data = data
      this.configInit()
    }
  },
  beforeMount () {
    // 如果只是展示
    if (this.displayOnly) {
      this.onlyDisplay = true
      this.type = 'display'
    }
    // 如果有本地配置，优先使用本地配置
    if (this.localConfig) {
      // 如果配置是json渲染器
      if (this.localConfig.designMode === 'json') {
        this.config = this.localConfig
        if (this.configData !== undefined) {
          this.config.data = Object.assign(this.config.data, this.configData)
        }
        this.jsonConfigInit()
      } else {
        // 如果配置是普通渲染器
        this.config = this.localConfig
        if (this.configData !== undefined) {
          this.config.data = Object.assign(this.config.data, this.configData)
        }
        if (this.config.data.images === undefined) {
          this.config.data.images = {}
        }
        this.configInit()
      }
    } else if (this.configName) {
      // 如果本地配置没有值，则从琉璃中获取
      this.initByConfigName()
    }
  },
  mounted () {
    // 如果外界传来了registerMap，我们将本VM对象注册到map中
    if (this.registerMap !== undefined) {
      this.registerMap.push(this)
    }
    // 将原始数据备份保存
    if (this.configData) {
      this.dataCache = JSON.parse(JSON.stringify(this.configData))
    } else if (this.config) {
      this.dataCache = JSON.parse(JSON.stringify(this.config.data))
    }
  }
}
</script>

<style lang="less" scoped>
.tools {
  text-align: center;
  cursor: pointer;

  .toolsItem {
    display: inline-block;
  }
}
</style>
