<template>
  <editorContainer
    :popup-type="popupType"
    :title="drawerName"
    :visible.sync="popupVisible"
    :before-close="handleClose"
    :destroy-on-close="true"
    :close-on-press-escape="false"
    :wrapper-closable="false"
    :append-to-body="true"
    :modal-append-to-body="true"
    v-bind="$attrs"
    :width="drawerWidth + 'px'"
    :style="{ '--drawer-width': drawerWidth }"
    custom-class="dialog-form-class"
    v-on="$listeners"
    @switch="handleSwitch"
  >
    <template :slot="popupType">
      <!-- 加上if销毁组件，否则重置还是第一次渲染的内容 -->
      <el-form
        v-if="popupVisible"
        ref="editConfig"
        :model="editConfig"
        :rules="editFormRules"
        label-width="128px"
        :inline="false"
        size="small"
        :disabled="loading"
      >
        <el-row :class="popupType === 'drawer' ? 'drawer-from-style' : 'dialog-from-style'">
          <!-- s 提示 -->
          <el-col v-show="config.addTip&&optType==='add'" :span="24" class="form-tip">
            {{ config.addTip }}
          </el-col>
          <el-col v-show="config.editTip&&optType==='edit'" :span="24" class="form-tip">
            {{ config.editTip }}
          </el-col>
          <!-- e 提示 -->
          <el-col v-for="(item, index) in renderSearchForm" :key="index" :span="24" :offset="0">
            <!-- s 每个模块的标题 -->
            <el-col v-if="item.header" class="edit-block--header" :span="24">
              {{ item.header }}
            </el-col>
            <!-- e 每个模块的标题 -->
            <!-- s 每个模块的列 -->
            <el-col
              v-for="(col, colIndex) in item.body"
              :key="colIndex"
              :span="colSpan(col.colSpan, col.type)"
              class="form-col-item"
            >
              <!-- 只显示文本 -->
              <el-form-item v-if="col.type === 'readonly'" :label="col.label" :required="col.required">
                <div style="display: flex">
                  <span style="margin-right: 10px">{{ editConfig[col.prop] }}</span>
                  <template v-if="col.btns">
                    <el-button
                      v-for="btn in col.btns"
                      :key="btn.label"
                      type="text"
                      @click="btn.method(editConfig[col.prop])"
                    >{{ btn.label }}
                    </el-button>
                  </template>
                </div>
              </el-form-item>
              <!-- 根据类型的不同处理不同的表单 -->
              <el-form-item v-else :prop="col.prop" :required="col.required" :label-position="col.labelPosition" v-show="col.vIf === undefined ? true : col.vIf && col.vIf(editConfig)">
                <template slot="label">
                  <span v-if="col.vIf === undefined ? true : col.vIf && col.vIf(editConfig)" v-html="col.label"/>
                  <el-tooltip class="item" effect="dark" placement="top">
                    <template slot="content">
                      <div v-html="col.labelTip"/>
                    </template>
                    <i v-if="col.labelTip" class="el-icon-warning-outline" style="margin-right: -5px"/>
                  </el-tooltip>
                </template>
                <template v-if="vIfRender(['input', 'textarea', 'text'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-input
                    v-model="editConfig[col.prop]"
                    :type="col.type"
                    :autosize="{ minRows: 2, maxRows: 4 }"
                    :placeholder="col.placeholder || '请输入'"
                    :disabled="isFieldDisabled(col)"
                    :readonly="col.readonly"
                    :maxlength="col.showWordLimit ? col.showWordLimit : null"
                    :show-word-limit="!!col.showWordLimit"
                    :clearable="clearable(col)"
                    style="width: 100%"
                    @input="col.listener && col.listener(editConfig[col.prop])"
                  />
                </template>
                <template v-else-if="vIfRender(['money', 'number'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-input
                    v-model="editConfig[col.prop]"
                    :placeholder="col.placeholder || '请输入'"
                    style="width: 100%"
                    :disabled="col.disabled"
                    :readonly="col.readonly"
                    :clearable="clearable(col)"
                    @input="handleFormatInput($event, col.prop, col.precision)"
                  />
                </template>
                <template v-else-if="vIfRender(['inputNumber'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-input-number
                    v-model="editConfig[col.prop]"
                    :min="col.min"
                    :max="col.max"
                    :step="col.step"
                    :step-strictly="col.stepStrictly"
                    :controls-position="col.controlsPosition"
                    :label="col.label"
                  />
                </template>
                <template v-else-if="vIfRender(['radio'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-radio-group v-model="editConfig[col.prop]" :placeholder="col.placeholder || '请选择'">
                    <el-radio v-for="option in col.options" :key="option.value" :label="option.value">{{
                        option.label
                      }}
                    </el-radio>
                  </el-radio-group>
                </template>
                <template v-else-if="vIfRender(['checkbox'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-checkbox-group v-model="editConfig[col.prop]" :placeholder="col.placeholder || '请选择'">
                    <el-checkbox v-for="option in col.options" :key="option.value" :label="option.value">{{
                        option.label
                      }}
                    </el-checkbox>
                  </el-checkbox-group>
                </template>
                <template v-else-if="vIfRender(['editor'], col.type, col.vIf && col.vIf(editConfig))">
                  <div class="wang-editor-render-area">
                    <!--                    <wangEditor v-model="editConfig[col.prop]" :exclude-keys="col.excludeKeys" style="width: 100%" />-->
                  </div>
                </template>
                <template v-else-if="vIfRender(['select'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-select
                    v-model="editConfig[col.prop]"
                    :placeholder="col.placeholder || '请选择'"
                    :disabled="isFieldDisabled(col)"
                    :readonly="col.readonly"
                    :clearable="clearable(col)"
                    :multiple="col.multiple"
                    style="width: 100%"
                  >
                    <el-option
                      v-for="option in col.options"
                      :key="option.value"
                      :label="option.label"
                      :value="option.value"
                    />
                  </el-select>
                </template>
                <template v-else-if="vIfRender(['switch'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-switch
                    v-model="editConfig[col.prop]"
                    :active-value="1"
                    :inactive-value="0"
                    active-color="#13ce66"
                    inactive-color="#ff4949"
                  />
                </template>
                <template v-else-if="vIfRender(['tree'], col.type, col.vIf && col.vIf(editConfig))">
                  <div class="tree-box">
                    <el-tree
                      :ref="col.prop"
                      :data="col.data"
                      :show-checkbox="col.showCheckbox === false ? false : true"
                      :default-expand-all="col.defaultExpandAll === false ? false : true"
                      :node-key="col.nodeKey || 'id'"
                      highlight-current
                      :props="col.defaultProps"
                      @check-change="handleCheckChange(col.prop)"
                    />
                  </div>
                </template>
                <template
                  v-else-if="vIfRender(['date', 'year', 'month', 'week', 'datetime', 'daterange'], col.type, col.vIf && col.vIf(editConfig))"
                >
                  <el-date-picker
                    v-model="editConfig[col.prop]"
                    :type="col.type"
                    :value-format="col.valueFormat || dateValueFormat(col.type)"
                    :format="col.format || dateValueFormat(col.type)"
                    :placeholder="col.placeholder || `请选择${col.label}`"
                    :clearable="clearable(col)"
                    style="width: 100%"
                    :picker-options="col.pickerOptions||{}"
                  />
                </template>
                <template
                  v-else-if="vIfRender(['dateDiy'], col.type, col.vIf && col.vIf(editConfig))"
                >
                  <el-date-picker
                    v-model="editConfig[col.prop]"
                    type="date"
                    :value-format="col.valueFormat || dateValueFormat('date')"
                    :format="col.format || dateValueFormat('date')"
                    :placeholder="col.placeholder || `请选择${col.label}`"
                    :clearable="clearable(col)"
                    style="width: 100%"
                    :picker-options="{
                        disabledDate: (time) => {
                      // 禁用特定日期范围
                      const startDate = new Date(editConfig[col.prop_disable])
                      const disableRange = time.getTime() < startDate.getTime()
                      return disableRange
                    }
                    }"
                  />
                </template>
                <template v-else-if="vIfRender(['uploadOneImage'], col.type, col.vIf && col.vIf(editConfig))">
                  <div>
                    <UploadOneImage v-model="editConfig[col.prop]" :api="col.api" :limit="col.limit"/>
                  </div>
                </template>
                <template v-else-if="vIfRender(['uploadImage'], col.type, col.vIf && col.vIf(editConfig))">
                  <div>
                    <uploadImage v-model="editConfig[col.prop]" :api="col.api" :limit="col.limit"/>
                  </div>
                </template>
                <template v-else-if="vIfRender(['uploadFile'], col.type, col.vIf && col.vIf(editConfig))">
                  <div>
                    <uploadFile v-model="editConfig[col.prop]" :data="col.data" :api="col.api"/>
                  </div>
                </template>
                <template v-else-if="vIfRender(['location'], col.type, col.vIf && col.vIf(editConfig))">
                  <div style="width: 100%">
                    <!-- <baiduGetLocation :point="editConfig[col.prop]" @getLocation="_getLocation" /> -->
                  </div>
                </template>
                <template v-else-if="vIfRender(['cascader'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-cascader
                    :ref="col.prop"
                    v-model="editConfig[col.prop]"
                    :options="col.options || areaOptions"
                    :clearable="clearable(col)"
                    :placeholder="col.placeholder || `请选择${col.label}`"
                    filterable
                    :disabled="isFieldDisabled(col)"
                    :props="Object.assign(cascaderProps, col.props)"
                    style="width: 100%"
                  />
                </template>
                <template v-else-if="vIfRender(['password'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-input
                    v-model="editConfig[col.prop]"
                    type="password"
                    placeholder="请输入密码"
                    :clearable="clearable(col)"
                    show-password
                    style="width: 100%"
                    class="password-strength"
                  >
                    <template v-if="pwdLevel" slot="append">
                      <div :class="pwdLevelColor[pwdLevel]">{{ pwdLevel }}</div>
                    </template>
                  </el-input>
                </template>
                <template v-else-if="vIfRender(['repassword'], col.type, col.vIf && col.vIf(editConfig))">
                  <el-input
                    v-model="editConfig[col.prop]"
                    type="password"
                    placeholder="请输入密码"
                    :clearable="clearable(col)"
                    show-password
                    style="width: 100%"
                  />
                </template>

                <template v-else-if="vIfRender(['buttons'], col.type, col.vIf && col.vIf(editConfig))">
                  <buttons v-model="editConfig[col.prop]"></buttons>
                </template>


                <template v-else-if="col.custom">
                  <slot :name="col.slotName || col.prop" :model="editConfig[col.prop]" :editConfig="editConfig"></slot>
                </template>
                <div v-if="col.bottomTip" class="form-item-bottom-tip" v-html="col.bottomTip"/>
              </el-form-item>
              <!-- 空表单占位 -->
              <el-col v-if="col.type === 'empty'" :span="colSpan(col.colSpan, col.type)">
                <div class="empty-form-item"/>
              </el-col>
            </el-col>
            <!-- e 每个模块的列 -->
          </el-col>
          <el-col :span="24" :class="popupType === 'drawer' ? 'fixed-footer' : 'dialog-footer'">
            <el-form-item label-width="0">
              <el-tooltip
                popper-class="button-save-tooltip"
                :disabled="!loading"
                effect="dark"
                content="正在保存，请勿点击!"
                placement="top"
              >
                <el-button type="primary" :loading="loading" @click="confirmSubmit()">保存</el-button>
              </el-tooltip>
              <el-button :disabled="loading" @click="handleReset()">重置</el-button>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </template>
  </editorContainer>
  <!-- </el-drawer> -->
</template>

<script>
import request from '@/utils/request'
// const wangEditor = () => import('@/components/wangEditor')
const uploadImage = () => import('@/components/UploadImage')
const UploadOneImage = () => import('@/components/UploadOneImage')
const uploadFile = () => import('@/components/UploadFile')
// const baiduGetLocation = () => import('@/components/BaiduGetLocation')
const editorContainer = () => import('@/components/Table/editorContainer')
const buttons = () => import('@/components/buttons')
export default {
  name: 'YMTableEditor',
  components: {
    // wangEditor,
    uploadImage,
    UploadOneImage,
    // baiduGetLocation,
    editorContainer,
    uploadFile,
    buttons
  },
  model: {
    prop: 'popupVisible',
    event: 'change'
  },
  props: {
    title: {
      type: String,
      default: ''
    },
    // 显示类型，弹窗(dialog)/抽屉(drawer)
    popupType: {
      type: String,
      default: 'dialog'
    },
    optType: {
      type: String,
      default: 'add'
    },
    popupVisible: {
      type: Boolean,
      default: false
    },
    // 弹窗配置
    config: {
      type: Object,
      default: () => ({
        title: '',
        addTip: '',
        editTip: '',
        size: ''
      })
    },
    // 编辑表单
    editForm: {
      type: Array,
      default: () => []
    },
    // 编辑的数据
    editData: {
      type: Object,
      default: () => ({})
    },
    apis: {
      type: Object,
      default: () => ({
        url: '',
        params: {}, // 提交的参数
        unique: {} // 唯一值判断的参数
      })
    }
  },
  data() {
    return {
      copyDataYuan:{},
      loading: false, // 请求loading
      isEdit: false, // 新增/编辑
      locateProp: '', // 使用百度地图定位的属性
      lntName: 'longitude',
      latName: 'latitude',
      apisParamsObj: {},
      editConfig: {},
      configMessge: {}, // 来自popupConfig信息
      splitParamsArray: [], // 记录需要拆分的参数
      editFormRules: {},
      formData: [],
      imageProps: [],
      treeProps: [],
      treeValues: {},
      areaOptions: [],
      cascaderProps: {
        expandTrigger: 'hover',
        checkStrictly: true,
        label: 'label',
        value: 'value',
        children: 'children'
      },
      cascaderPropsArr: [], // 存在的cascader
      // 密码参数设置
      pwdLevel: '',
      pwdLevelColor: {
        弱: 'danger',
        中: 'warning',
        强: 'success'
      },
      checkPwd: (rule, value = '', callback) => {
        if (this.isEdit && value === '') {
          return callback()
        } else if (value === '') {
          return callback(new Error('请输入密码'))
        } else if (value.length < 8) {
          this.pwdLevel = ''
          return callback(new Error('密码需要大于8位'))
        } else if (!value.match(/^[A-Za-z0-9]+$/)) {
          this.pwdLevel = ''
          return callback(new Error('密码只能英文字母和数字'))
        }

        var level = 0
        if (value.match(/[A-Z]/)) {
          level = level + 1
        }
        if (value.match(/[a-z]/)) {
          level = level + 1
        }
        if (value.match(/[0-9]/)) {
          level = level + 1
        }

        if (level === 1) {
          this.pwdLevel = '弱'
          return callback(new Error('密码强度太弱'))
        } else if (level === 2) {
          this.pwdLevel = '中'
        } else if (level === 3) {
          this.pwdLevel = '强'
        }

        return callback()
      },
      checkRePwd: (rule, value = '', callback) => {
        console.log('🚀 this.isEdit', value)
        if (!String(this.editConfig.password).includes(value)) {
          console.log('🚀 this.isEdit22', this.editConfig.password, value)
          callback(new Error('两次密码输入不一致'))
        } else if (this.isEdit && value === '' && this.editConfig.password === '') {
          callback()
        } else if (value === '') {
          callback(new Error('请再次输入密码'))
        } else {
          callback()
        }
      }
    }
  },
  computed: {
    clearable() {
      return item => {
        return item.clearable !== undefined ? item.clearable : true
      }
    },
    // 布局默认列数
    colSpan() {
      return (colSpan, type) => {
        let colSpanValue = 24
        if (this.config?.size === 'small') return 24
        const typeColspan = {
          textarea: 24,
          editor: 24,
          uploadImage: 24,
          baiduGetLocation: 24,
          tree: 24,
          cascader: this.popupType === 'drawer' ? 24 : 12
        }
        if (colSpan) {
          colSpanValue = colSpan
        } else if (typeColspan[type]) {
          colSpanValue = typeColspan[type]
        } else {
          colSpanValue = this.popupType === 'drawer' ? 24 : 12
        }
        return colSpanValue
      }
    },
    // 用于渲染表单，处理在渲染前做的特殊处理，返回渲染的参数
    renderSearchForm() {
      return this.editForm
    },
    drawerWidth() {
      const width = this.popupType === 'drawer' ? '500' : '960'
      console.log('popupConfig', this.config)
      if (!this.config?.size) return width
      const popupSize = {
        small: '480',
        medium: '720',
        large: '960'
      }
      return popupSize[this.config.size] || width
    },
    // 弹窗名称
    drawerName() {
      return this.title || this.editData.id ? '编辑' : '新增'
    },
    // 日期值格式配置
    dateValueFormat() {
      return type => {
        const valueFormat = {
          year: 'yyyy',
          month: 'yyyy-MM',
          date: 'yyyy-MM-dd',
          dates: 'yyyy-MM-dd',
          months: 'yyyy-MM',
          years: 'yyyy',
          week: 'yyyy-ww',
          datetime: 'yyyy-MM-dd HH:mm:ss',
          datetimerange: 'yyyy-MM-dd HH:mm:ss',
          daterange: 'yyyy-MM-dd'
        }
        return valueFormat[type]
      }
    },
    // 是否显示，用于表单渲染
    vIfRender() {
      return (types, showType, vIf) => {
        const vIfFlag = vIf === undefined ? true : vIf
        return types.includes(showType) && vIfFlag
      }
    }
  },
  watch: {
    // 初始化数据
    popupVisible: {
      handler(newVal, oldVal) {
        this.$emit('change', newVal)
        // 初始化页面和数据
        if (newVal) {
          this.copyDataYuan=this.editData
          console.log('🚀 获取列表editData:', this.editData)
          this.isEdit = !!this.editData.id
          // 过滤表单数据，用于渲染表单
          this.formData = []
          this.editForm.forEach(element => {
            this.formData = this.formData.concat(...element.body)
          })
          console.log('🚀 重构配置formData:', this.formData)
          // 初始化数据
          this.imageProps = []
          this.cascaderPropsArr = []
          this.editConfig = Object.assign(
            {},
            ...this.formData.map(item => {
              const propName = item?.propAlias || item.prop
              // 是否需要过滤
              if (item.dealWidthParams) {
                return {
                  [item.prop]: item.dealWidthParams(this.editData)
                }
              } else if (item.filter) {
                if (item.type === 'radio') {
                  return { [item.prop]: this.labelToValue(this.editData[propName], item.options) || item.default }
                } else if (item.type === 'checkbox') {
                  return { [item.prop]: this.formatChekboxLabelToValue(this.editData[propName], item.options) || item.default }
                }
              } else if (item.type === 'radio') {
                const val = this.editData[propName]

                return { [item.prop]: [null, undefined].includes(val) ? item.default || '' : val + '' }
              } else if (item.type === 'checkbox') {
                return { [item.prop]: this.formatChekboxValue(this.editData[propName], item.options) || item.default }
              } else if (item.type === 'tree') {
                let treeValue = this.editData[propName]
                this.treeProps = []
                this.treeValues = {}
                this.treeProps.push(item.prop)
                if (treeValue && !Array.isArray(treeValue)) {
                  treeValue = JSON.parse(treeValue)
                }
                const treeValues = { [item.prop]: treeValue || item.default || [] }
                this.treeValues = Object.assign({}, treeValues)
                return treeValues
              } else if (item.type === 'uploadImage') {
                let imgValue = this.editData[propName]
                this.imageProps.push(item.prop)
                let imgList = []
                if (String(imgValue).includes('[]')) {
                  imgList = []
                } else if (Array.isArray(imgValue)) {
                  if (!imgValue.length) return []
                  imgList = imgValue.map(item => {
                    return { name: this.formatUrl(item), url: this.formatUrl(item) }
                  })
                } else {
                  if (String(imgValue).includes('[') && String(imgValue).includes('[') && !String(imgValue).includes('[]')) {
                    imgValue = JSON.parse(imgValue)
                  }
                  if (!imgValue) {
                    return []
                  }
                  const arr = Array.isArray(imgValue) ? imgValue : String(imgValue || '').split(',')
                  imgList = arr.map(item => {
                    return { name: this.formatUrl(item), url: this.formatUrl(item) }
                  })
                }
                return { [item.prop]: imgList }
              } else if (['date', 'year', 'month', 'week', 'datetime'].includes(item.type)) {
                return { [item.prop]: Object.keys(this.editData).length ? String(this.editData[propName]) || item.default : item.default || '' }
              } else if (item.type === 'cascader') {
                this.cascaderPropsArr.push(item.prop)
                if (item.splitParams) {
                  this.splitParamsArray.push(item)
                  console.log('🚀 存在拆分参数：', item)
                  const splitArr = []
                  for (const name in item.splitParams) {
                    if (this.editData[name]) {
                      splitArr.push(this.editData[name])
                    }
                  }
                  this.areaOptions = []
                  if (item.areaOptions) {
                    this.areaOptions = [...item.areaOptions]
                  }
                  return { [item.prop]: item.default || splitArr }
                } else {
                  return { [item.prop]: this.editData[item.prop] }
                }
              } else if (item.type === 'location') {
                // 这里需要记录经度纬度的属性名称，该属性不在提交参数内，提交前删除
                this.locateProp = item.prop
                this.lntName = item.lntName || 'longitude'
                this.latName = item.latName || 'latitude'
                return {
                  [item.prop]: {
                    address: this.editData[propName],
                    longitude: this.editData[this.lntName],
                    latitude: this.editData[this.latName]
                  }
                }
              } else if (item.type !== 'empty') {
                const val = this.editData[propName]

                return { [item.prop]: [null, undefined].includes(val) ? item.default || '' : val }
              }
            })
          )
          console.log('🚀 初始化的数据editConfig：', this.editConfig)
          // 规则
          this.editFormRules = Object.assign(
            {},
            ...this.formData.map(item => {
              if (item.rules && item.type !== 'empty') {
                return { [item.prop]: item.rules || [] }
              } else if (item.type === 'password') {
                this.pwdLevel = ''
                return { [item.prop]: [{ validator: this.checkPwd, trigger: 'change' }] }
              } else if (item.type === 'repassword') {
                return { [item.prop]: [{ validator: this.checkRePwd, trigger: 'change' }] }
              }
            })
          )
          console.log('🚀 编辑的规则editFormRules：', this.editFormRules)
          // 是否是区域展示
          const existCasader = this.formData.find(item => item.isArea)
          if (existCasader) {
            console.log('🚀 获取区域数据……')
            this.areaList(existCasader.isArea)
          }
          // 清除所有的校验
          this.$nextTick(() => {
            if (this.$refs.editConfig) {
              console.log('🚀 清除所有的校验……')
              this.$refs.editConfig.clearValidate()
            }
            // 初始化树数据
            if (this.treeProps.length) {
              console.log('🚀 获取数数据……')
              this.setTreeChecked()
            }
          })
        }
      },
      immediate: true
    },
    editConfig: {
      handler(val) {
        this.$emit('onValueChange', val)
      },
      deep: true
    }
  },
  methods: {
    isFieldDisabled(col) {
      const { disabled } = col;
      // 布尔值直接返回
      if (typeof disabled === 'boolean') return disabled;
      // 函数则调用并传递数据
      if (typeof disabled === 'function') {
        try {
          return disabled(this.copyDataYuan);
        } catch {
          return false;
        }
      }
      return false;
    },
    // TODO: 切换弹窗类型，切换的时候回显上会有问题，待提
    handleSwitch(value) {
      this.popupType = value
      this.popupVisible = false
      this.$nextTick(() => {
        this.popupVisible = true
      })
    },
    /**
     * 格式化图片地址,返回的结果是有带域名的图片链接
     * @param {*} url 需要格式化的链接
     */
    formatImageUrl(url) {
      if (!url) return ''
      if (String(url) === '[]') {
        return ''
      } else if (String(url).includes('http')) {
        return url
      } else {
        if (!url) return ''
        // 判断url首字母是不是斜杆
        if (url.charAt(0) !== '/') {
          url = `/${url}`
        }
        const host = this.apis.imgApi || process.env.VUE_APP_BASE_IMG
        return `${host}${url}`
      }
    },
    formatUrl(url) {
      if (String(url).includes('[]')) {
        return []
      } else if (Array.isArray(url)) {
        return this.formatImageUrl(url[0])
      } else {
        if (String(url).includes('[') && String(url).includes(']') && !String(url).includes('[]')) {
          const arr = typeof url === 'string' ? JSON.parse(url) : url
          return this.formatImageUrl(arr[0])
        } else if (String(url).includes('http')) {
          return `${url}`
        } else {
          return this.formatImageUrl(url)
        }
      }
    },
    /**
     * money和number格式化，可输入正数、负数和保留两位小数
     * @param {*} e input值
     * @param {*} prop 当前表单字段
     */
    //  TODO: precision无法随机值问题
    handleFormatInput(e, prop, precision = 2) {
      let value = e.replace(/[^\-\d.]/g, '') // 只能输入.和-和数字
      value = value.replace(/^\./g, '') // 第一个字符不能是.
      value = value.replace(/\.{2,}/g, '.') // 不能连续输入.
      value = value.replace(/(\.\d+)\./g, '$1') // .后面不能再输入.
      value = value.replace(/(-)\./g, '$1') // -后面不能输入.
      value = value.replace(/\-{2,}/g, '-') // -只能保留一个
      value = value.replace(/(\d+|\.)-/g, '$1') // 数字和.后面不能接-,不能出现类似11-, 12.-
      value = value.replace(/-(0){2,}/g, '$1') // 不能出现-00,-001,-0001类似
      value = value.replace(/(-)0+(\d+)/g, '$1$2') // 不能出现-01,-02类似
      value = value.replace(/^0+(\d)/, '$1') // 第一位0开头，0后面为数字，则过滤掉，取后面的数字
      value = value.replace(/(\d{15})\d*/, '$1') // 最多保留15位整数
      if (precision === 3) {
        value = value.replace(/(\.\d{3})\d*/, '$1')
      } else if (precision === 4) {
        value = value.replace(/(\.\d{4})\d*/, '$1')
      } else if (precision === 0) {
        value = parseFloat(value) || ''
      } else {
        value = value.replace(/(\.\d{2})\d*/, '$1')
      }
      this.editConfig[prop] = value
    },
    /**
     * 获取地区列表
     * 判断数组对象里的type是否有cascader,一般为4或1
     *  type 为1只有县
     *  type 为2有县加下一级
     *  type 为3有街道镇
     *  type 为4有市县街道镇，true为该值
     *  type 为5有市本级
     * @param {*} type
     */
    areaList(type) {
      if (![true, 1, 2, 3, 4, 5].includes(type)) {
        this.$message.error('请设置isArea为1/2/3/4/5/true')
        return
      }
      request({
        url: `/lv/area_list`,
        method: 'get',
        params: {
          type: type === true ? 4 : type
        }
      }).then(res => {
        // 由于获取出来的数据结构不一样，所以需要根据type来获取数据
        if ([true, 4].includes(type)) {
          this.areaOptions = this.areaOptions.concat(res.data[0].children)
        } else if ([1, 2, 3].includes(type)) {
          this.areaOptions = this.areaOptions.concat(res.data)
          if ([1, 3].includes(type)) {
            this.cascaderProps = Object.assign({}, this.cascaderProps, {
              label: 'name',
              value: 'id'
            })
          }
        }
      })
    },
    /**
     * 百度地图获取地址坐标方法
     * @param {*} point
     */
    _getLocation(point) {
      const { longitude, latitude } = point
      console.log('🚀 地图坐标数据：', point)
      if (longitude && latitude) {
        this.editConfig[this.locateProp] = {
          address: point.address,
          longitude,
          latitude
        }
        this.editConfig[this.lntName] = longitude
        this.editConfig[this.latName] = latitude
      }
    },
    /**
     * 树形结构选择
     * 这边的选择会返回上级的id
     * @param {*} refName
     */
    handleCheckChange(refName) {
      const result = this.$refs[refName][0].getCheckedNodes(false, true)
      console.log('🚀 树选择后最新的数据', result)
      this.editConfig[refName] = result.map(item => item.id)
    },
    /**
     * 树组件的回显
     */
    setTreeChecked() {
      if (!this.editConfig[this.treeProps[0]]) return
      this.$nextTick(() => {
        this.treeProps.forEach(prop => {
          if (this.$refs[prop]) {
            this.editConfig[prop].forEach(element => {
              this.$refs[prop][0].setChecked(element, true, false)
            })
            // this.$refs[prop][0].setCheckedKeys(this.editConfig[prop])
          }
        })
      })
    },
    /**
     * 表单渲染的过程中，如果filter为true，则根据提供的options转换为value值
     * @param {*} label
     * @param {*} options
     */
    labelToValue(label, options) {
      if (label === undefined || label === null) return false
      return options.find(item => item.label === label)?.value
    },
    /**
     * 提交参数处理
     * 根据options将选择的lable转换为value值
     * @param {*} labels
     * @param {*} options
     */
    formatChekboxLabelToValue(labels, options) {
      if (Array.isArray(labels)) {
        return labels.map(label => this.labelToValue(label, options))
      } else {
        return this.formatChekboxLabelToValue(String(labels).split(','), options)
      }
    },
    /**
     * 回显格式化
     * 处理回显的value值，如果是数组，则直接返回数组，如果是字符串，则将字符串拆分为数组
     * @param {*} labels
     * @param {*} options
     */
    formatChekboxValue(labels, options) {
      if (Array.isArray(labels)) {
        return labels
      } else {
        return String(labels).split(',')
      }
    },
    // 关闭弹窗
    handleClose(done) {
      // this.$refs.editConfig.clearValidate()
      this.$emit('change', false)
    },
    /**
     * 确认提交之前是否给出提示
     * 主要是根据alert参数判断是否需要提示，提示内容固定
     */
    confirmSubmit() {
      this.$refs.editConfig.validate(valid => {
        if (valid) {
          if (this.editConfig?.buttons) {
            this.editConfig.buttons = this.editConfig?.buttons.filter(item =>
              item && Array.isArray(item) && item.length > 0
            )
          }
          this.apisParamsObj = this.apis[this.isEdit ? 'edit' : 'add']
          if (this.apisParamsObj?.alert) {
            this.$confirm(alert.content || '确认提交吗?', alert.title || '提示', {
              confirmButtonText: alert.confirmButtonText || '确定',
              cancelButtonText: alert.cancelButtonText || '取消',
              dangerouslyUseHTMLString: true,
              type: 'warning'
            })
              .then(() => {
                if(this.editForm[0] && this.editForm[0].customHandle && this.editForm[0].customHandle.submit) {
                  this._dealWithParams({}).then(params => {
                    this.editForm[0].customHandle.submit({
                      params,
                      handleClose: this.handleClose,
                    })
                  })
                } else {
                  this.handleSubmit()
                }

              })
              .catch(() => {
                // 暂不提交
              })
          } else {
               if(this.editForm[0] && this.editForm[0].customHandle && this.editForm[0].customHandle.submit) {
                this._dealWithParams({}).then(params => {
                    this.editForm[0].customHandle.submit({
                      params,
                      handleClose: this.handleClose,
                    })
                })
              } else {
                this.handleSubmit()
              }
          }
        }
      })
    },
    /**
     * 提交事件
     * @param {*} obj
     */
    handleSubmit(obj = {}) {
      this._dealWithParams(obj).then(params => {
        console.log('🚀 提交的参数：', params)
        this.editRequest(params).then(res => {
          const coverFlag = this.apisParamsObj?.coverFlag || 'is_confirm'
          this.handleSubmit({
            // 该参数默认为is_confirm,如果不是需要自己自定义或者和服务端打一架
            [coverFlag]: 1
          })
        })
      })
    },
    /**
     * 处理提交的参数
     * @param {*} obj
     */
    _dealWithParams(obj) {
      return new Promise((resolve, reject) => {
        // 提交的参数处理
        const params = Object.assign({}, this.editConfig, obj)
        if (this.editData && Object.keys(this.editData).length !== 0) {
          Object.assign(params, {
            id: this.editData.id
          })
        }
        console.log('🚀 编辑提交的参数(未处理)：', params)
        // 是否有需要拆解的参数
        console.log('🚀 需要拆解的参数：', this.splitParamsArray)
        if (this.splitParamsArray.length) {
          this.splitParamsArray.forEach(item => {
            if (item.splitParams) {
              let _index = 0
              for (const key in item.splitParams) {
                if (Object.hasOwnProperty.call(item.splitParams, key)) {
                  params[key] = params[item.prop][_index++] || ''
                }
              }
              // 卸磨杀驴，赋值完后需要删除原来的prop，这里不会删除表单的属性
            } else {
              this.$message.warning(`请设置${item.prop}属性的拆解参数splitParams`)
            }
          })
        }
        // 处理图片参数
        console.log('🚀 处理图片参数：', this.imageProps, this.apis.imgApi)
        if (this.imageProps && this.imageProps.length) {
          this.imageProps.forEach(item => {
            if (params[item]) {
              if (Array.isArray(params[item]) && params[item].length) {
                params[item] = params[item].map(item => {
                  const str = String(item.url || item)
                  if (str.includes('http')) {
                    const reg = this.apis.imgApi
                    const url = str.replaceAll(reg, '')
                    // TODO: 去掉url前面多余的斜杠
                    if (url.startsWith('/')) {
                      return url.substring(1)
                    }
                    return url
                  } else {
                    return str || []
                  }
                })
              } else {
                params[item] = params[item].url || params[item] || []
              }
            } else {
              params[item] = []
            }
          })
        }
        resolve(params)
      })
    },
    /**
     * 新增编辑接口处理，处理最后的提交参数
     * @param {*} params
     */
    editRequest(params = {}) {
      return new Promise((resolve, reject) => {
        // 特殊处理，添加到url后面的参数
        let additionParams = ''
        if (this.apisParamsObj?.additionParams && this.apisParamsObj.additionParams.length) {
          additionParams = this.apisParamsObj?.additionParams
            .map(item => {
              return params[item]
            })
            .join('/')
          additionParams = '/' + additionParams
        }
        // 自定义特殊处理参数
        if (this.apisParamsObj?.dealWithParams) {
          // 返回默认的提交参数params和表格初始化的参数，主要用于提取一些配置
          params = this.apisParamsObj.dealWithParams(params, this.formData)
        }
        // 是否删除没有值或者为空的参数
        if (this.apisParamsObj?.deleteEmpty) {
          for (const key in params) {
            if (Object.hasOwnProperty.call(params, key)) {
              if (params[key] === undefined || params[key] === null || params[key] === '') {
                delete params[key]
              }
            }
          }
        }
        // deleteParams 删除参数
        if (this.apisParamsObj?.deleteParams) {
          for (const key in params) {
            if (Object.hasOwnProperty.call(params, key)) {
              if (this.apisParamsObj.deleteParams.includes(key)) {
                delete params[key]
              }
            }
          }
        }
        // 拆分参数删除，主要是县镇村地址
        if (this.splitParamsArray.length) {
          this.splitParamsArray.forEach(item => {
            if (item.splitParams) {
              delete params[item.prop]
            }
          })
        }
        // 如果有获取经纬度地址的参数，需要删除
        if (this.locateProp) {
          delete params[this.locateProp]
        }
        // 提交 id字段 不匹配替换
        if (this.apisParamsObj?.idPro) {
          params.id = params[this.apisParamsObj.idPro] = this.editData.id
        }
        console.log('🚀 最后提交的参数：', params)
        this.loading = true
        request({
          url: this.apisParamsObj?.url + additionParams,
          method: this.apisParamsObj?.method || 'post',
          data: params
        })
          .then(res => {
            this.loading = false
            if ([200, 0].includes(res.code)) {
              this.$message({
                type: 'success',
                message: '提交成功！'
              })
              this.handleClose()
              console.log(this.$listeners)
              if (this.$listeners?.callback) {
                this.$emit('callback', res)
              }
            }
          })
          .catch(err => {
            this.loading = false
            reject(err)
          })
      })
    },
    /**
     * 重置表单
     * 图片的重置需要特殊处理
     */
    handleReset() {
      this.$refs.editConfig.resetFields()
      // 如果是新增
      if (!this.isEdit) {
        // 图片重置特俗处理
        if (this.imageProps && this.imageProps.length) {
          this.imageProps.forEach(item => {
            this.editConfig[item] = []
          })
        }
        // el-tree清空处理
        if (this.treeProps && this.treeProps.length) {
          this.treeProps.forEach(item => {
            this.$refs[item][0].setCheckedKeys([])
          })
        }
      } else {
        if (this.treeProps && this.treeProps.length) {
          this.treeProps.forEach(item => {
            this.$refs[item][0].setCheckedKeys(this.treeValues[item])
          })
        }
      }
    }
  }
}
</script>
<style lang="scss" scoped>
.form-tip {
  height: 20px;
  margin-bottom: 16px;

  color: #ff4949;

  font-size: 14px;
  line-height: 20px;
}

.el-form-item--small.el-form-item {
  display: flex;
  align-items: center;
}

::v-deep .el-form-item--small .el-form-item__label {
  flex-shrink: 0;

  font-weight: 400;
  line-height: 16px;
}

::v-deep.el-form-item--small .el-form-item__content {
  width: 100%;
  margin-left: 0 !important;
}

::v-deep.password-strength {
  .el-input-group__append {
    overflow: hidden;

    width: 32px;
    padding: 0;

    text-align: center;

    border: none;

    line-height: 32px;
  }
}

::v-deep label.el-checkbox,
::v-deep label.el-radio {
  min-width: calc(33% - 16px);
  margin-right: 16px;

  line-height: 32px;
}

.edit-block--header {
  position: relative;

  padding: 10px 0 10px 9px;

  color: #333;

  font-size: 16px;
  line-height: 23px;

  &::before {
    position: absolute;
    top: 14px;
    left: 0;

    display: inline-block;

    height: 15px;

    content: '';

    border-left: 3px solid #409eff;
  }
}

.el-drawer__body {
  position: relative;

  .el-form {
    margin-bottom: 56px;
  }

  .el-row {
    padding-right: 40px;
  }
}

.tree-box {
  overflow-y: auto;

  max-height: 300px;

  border: 1px solid #eee;

  ::v-deep label.el-checkbox {
    min-width: auto;
  }
}

.danger {
  color: #fff;
  background-color: #ff4949;
}

.warning {
  color: #fff;
  background-color: #e6a23c;
}

.success {
  color: #fff;
  background-color: #52c41a;
}

.empty-form-item {
  height: 33px;
}

.form-item-bottom-tip {
  position: absolute;
  top: 100%;
  left: 0;

  color: #9e9e9e;

  font-size: 12px;
  line-height: 16px;
}

::v-deep .el-form-item__error {
  width: 100%;

  background-color: #fff;
}

::v-deep .el-message-box__status {
  top: 18%;
}
</style>
<style lang="scss">
.dialog-form-class {
  .el-dialog__header {
    padding: 16px 24px;

    color: #333;
    box-shadow: inset 0px -1px 0px 0px #f0f0f0;

    font-size: 16px !important;
  }

  .dialog-footer {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;

    display: flex;
    justify-content: flex-end;

    height: 72px;
    padding-right: 20px;

    text-align: center;
    // border-top: 1px solid rgba(231, 231, 231, 1);

    background-color: #ffffff;

    .el-form-item {
      margin-bottom: 0;
    }
  }

  .fixed-footer {
    position: fixed;
    right: 0;
    bottom: 0;

    display: flex;
    align-items: center;
    justify-content: center;

    width: var(--drawer-width);
    height: 56px;

    border-top: 1px solid rgba(231, 231, 231, 1);
    background-color: #ffffff;

    .el-form-item--mini.el-form-item,
    .el-form-item--small.el-form-item {
      margin-bottom: 0;
    }
  }

  .el-dialog__body {
    overflow: hidden;
    overflow-y: auto;

    max-height: calc(100vh - 200px);
    padding: 40px 20px 72px;

    .el-row {
      position: static;

      margin-right: -80px;

      & > .el-col {
        & > .el-col {
          padding-right: 80px;
        }
      }
    }
  }
}
</style>
