
<template>
  <div :id='elId' class="selectBoxPlus" style='width:100%;height:100%;'>
     <div class="contarnBox" style='width:100%;height:100%;'>
      <div class="selectTitle" v-show="configData.title">{{configData.title}}</div>
      <div class="selectCurr" style='width:100%;height:100%;'>
          <el-select
                :allow-create='configData.allowCreate'
                :default-first-option='configData.defaultFirstOption'
                style="width:100%"
                :class="{'noneStyle':isReadOnly1,'noneStyle2':isReadOnly2}"
                :size='configData.size'
                @clear="clear_select"
                :collapse-tags="configData.collapse_tags"
                :multiple="configData.multiple"
                :disabled="isReadOnly"
                :clearable="configData.clearable"
                ref="select_demo"
                @change="change"
                @focus="select_focus"
                v-model="value_inner"
                :filterable="configData.filterable"
                :remote="configData.remote"
                :remote-method="remoteMethod_"
                :placeholder="configData.placeholder"
              >
            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
          </el-select>
          <el-tooltip v-if='linkBtnUiVis'  el-tooltip content="主表" placement="bottom" effect="light">
               <el-button size="mini" @click='jumpSelect' circle icon="el-icon-s-promotion"></el-button>
          </el-tooltip>
      </div>
    </div>
      <jsoneditor
          v-model='jsoneditorVisible'
          :elInfo='elInfo'
          :jsoneditorData='editData'
          :jsoneditorCloseAfter='jsoneditorCloseAfter'
          :jsoneditorOpenAfter='jsoneditorOpenAfter'
          >
        </jsoneditor>
        <dialogIframe @closeDialog='closeDialog' v-if='linkBtnUiVis' @linkBtnUiBack='linkBtnUiBack'   v-model="dialogIframeVisible" :src='dialogIframeSrc'></dialogIframe>
    </div>
</template>

<script>
import uuidv1 from 'uuid/v1'
import jsoneditor from '../common/jsoneditor'
import mockData from '../common/initDbConfigDataJson'
import ucComponent from '../ucClass/uc_component'
import _ from 'lodash'
import commonUtility from '../funTools/commonUtility'
import dialogIframe from '../common/dialogTemplate/dialogIframe'
export default {
  mixins: [ucComponent],
  name: 'hsSelectPlus',
  components: {
    jsoneditor, dialogIframe
  },
  props: {
    remoteMethod: {
      type: Function,
      default() {
      }
    },
    containerType: {},
    elInfo: {
      type: Object,
      default() {
        return {}
      }
    },
    allSourceData: {
      type: Object,
      default() {
        return {}
      }
    },
    jsoneditorCloseAfter: {
      type: Function,
      default() {
        return () => {}
      }
    },
    jsoneditorOpenAfter: {
      type: Function,
      default() {
        return () => {}
      }
    },
    value: '',
    writeBackObject: {
      default() {
        return {}
      }
    },
    readonly: {
      default: false
    }
  },
  data() {
    return {
      options: [],
      value_inner: this.multiple ? [] : '',
      filterable: false,
      remote: false,
      // url_static: 'commonUtilAPI/ref/items/',
      // url_dynamic: 'commonUtilAPI/ref/table/',
      url_static: 'commonUtilAPI/',
      url_dynamic: 'commonUtilAPI/ref/table/',
      url_ipCommonAPI: 'ipCommonAPI/',
      real_url: '',
      elId: '',
      chart: null,
      jsoneditorVisible: false, // 是否显示动态配置的弹框
      editData: {
        config: {},
        sourceData: [],
        sql: ''
      },
      configData: {
        url: '',
        ref: {
          const_id: '',
          table_name: '',
          columns: '',
          remote_condition: '',
          displayfield: '', // 默认值
          writebackfield: []
        },
        multiple: false,
        collapse_tags: true,
        disabled: false,
        size: 'mini',
        clearable: true,
        title: '',
        value: '',
        label: '',
        parms: {},
        placeholder: '请选择',
        is_computed: false,
        remote: false,
        filterable: false
      },
      emptyList: [undefined, 'undefined', null, 'null', ''],
      number: 0,
      menuGlobalParams: {},
      focus: false,
      writeBackObject_: {},
      dialogIframeSrc: '',
      dialogIframeVisible: false,
      linkBtnUiVis: false,
      linkUiBtnTxt: '调整'
    }
  },
  computed: {
    dialogIfameVis: function() {
      const linkBtnUi = !!this.configData.linkBtnUi
      return linkBtnUi
    },
    isReadOnly: function() {
      return this.readonly || this.configData.disabled
    },
    isReadOnly1: function() {
      if (this.containerType !== 'editArea' && (this.readonly || this.configData.disabled)) {
        return true
      }
    },
    isReadOnly2: function() {
      // 是编辑框
      if (this.containerType === 'editArea' && (this.readonly || this.configData.disabled)) {
        return true
      }
    }
  },
  watch: {
    writeBackObject: {
      handler(newValue, oldValue) {
        const linkProp = this.configData.linkProp
        const displayfield = this.configData.ref.displayfield
        const remote_condition = this.configData.ref.remote_condition
        const newData = newValue[linkProp]
        const oldData = this.writeBackObject_[linkProp]
        if (linkProp && newData !== oldData) {
          this.value_inner = ''
          this.$emit('input', '')
          this.writeBackObject[displayfield] = ''
          if (remote_condition) {
            this.remoteMethod_()
          }
        }
        this.writeBackObject_ = _.cloneDeep(newValue)
      },
      deep: true
    },
    value: {
      handler(newValue, oldValue) {
        this.initValue(newValue)
      },
      deep: true
    },
    allSourceData: {
      handler: function(newVal, oldVal) {
        this.number += 1
        if (this.number <= 1) {
          this.initData(newVal)
          this.initValue(this.value)
        }
      },
      deep: true
    }
  },
  created() {
    this.elId = uuidv1() // 获取随机id
  },
  mounted() {
    this.$nextTick(() => {
      this.placeholder = this.elInfo.placeholder
      this.title = this.elInfo.title
      this.initData(this.allSourceData)
      this.initValue(this.value)
    })
  },
  methods: {
    closeDialog() {
      this.dialogIframeVisible = false
    },
    linkBtnUiBack(data) {
      debugger
      const linkBtnUi = this.configData.linkBtnUi
      if (!linkBtnUi) return
      const writeProp = linkBtnUi.writeProp || {}
      for (const key in writeProp) {
        const value = writeProp[key]
        this.$set(this.writeBackObject, key, data[value])
      }
      this.dialogIframeVisible = false
    },
    jumpSelect() {
      const item = this.configData.linkBtnUi
      const { url, dyncQueryParms, newDefault } = item
      const newDefaultStr = JSON.stringify(newDefault)
      const parms = _.cloneDeep(dyncQueryParms || {})
      parms.newDefault = newDefaultStr
      const href = location.href
      const startUrl = href.split('#')[0]
      let url_ = url
      const parseQuery = commonUtility.parseUrlQueryString()
      const { db_name } = parseQuery
      if (db_name) {
        parms.db_name = db_name
      }
      if (item.url.includes('?')) {
        url_ = url + '&fromMenu=1'
      } else {
        url_ = url + '?fromMenu=1'
      }
      let parmsStr = ''
      for (const key in parms) {
        parmsStr += `&${key}=${parms[key]}`
      }
      const url__ = `${startUrl}#${url_}` + parmsStr + '&isInnerDialog=1'
      this.dialogIframeSrc = url__
      this.dialogIframeVisible = true
    },

    disAbledFun() {
      return this.readonly || this.configData.disabled
    },
    initValue(value) {
      if (!Object.keys(this.allSourceData.config || {}).length) return
      const is_computed = this.configData.is_computed
      const { multiple } = this.configData
      if (is_computed) {
        // 计算模式
        this.value_inner = this.ten_twe_tans(value)
      } else {
        if (multiple) {
          this.value_inner = value ? value.split(',') : []
        } else {
          this.value_inner = value
        }
        if (value === null || value === 'null') {
          this.value_inner = ''
        }
        this.setDefault()
      }
    },
    getSysParams() {
      const { db_name, is_mock, db_code } = commonUtility.parseUrlQueryString()
      const { appCode, pagename } = commonUtility.parseUrlQueryBIDyncAppcodePageName()
      const isMock = this.emptyList.includes(is_mock) ? 1 : is_mock
      const dbName = db_name || ''
      const obj = _.cloneDeep({
        dbName,
        appCode,
        page: pagename,
        isMock,
        db_code
      })
      return obj
    },
    mergeCinfig(config1, config2) {
      Object.assign(config1, config2)
    },
    initConfig(config) {
      this.mergeCinfig(this.configData, _.cloneDeep(config))
      if (this.configData.ref) {
        this.configData.remote = !!this.configData.ref.remote_condition
        this.configData.filterable = !!this.configData.ref.remote_condition
      }
      const linkBtnUi = this.configData.linkBtnUi
      this.linkBtnUiVis = !!linkBtnUi
      if (this.linkBtnUiVis) {
        this.linkUiBtnTxt = this.configData.linkBtnUi.label
      }
    },
    async initData(allSourceData) {
      const { config, sourceData, is_mock } = _.cloneDeep(allSourceData)
      this.is_mock = is_mock
      if (!sourceData) {
        this.initMockData()
      } else {
        this.initConfig(config)
        this.dealWithData(sourceData)
      }
    },
    autoAddNullValue(data) {
      const sourceData = _.cloneDeep(data)
      if (Array.isArray(sourceData)) {
        const list = sourceData.map(item => {
          if (item.value !== '') {
            return Number(item.value)
          }
        })
        const hasNaN = list.find(item => isNaN(item))
        const zeroTarget = list.find(item => item === 0 || item === '0')
        let hasZero = false
        if (zeroTarget === 0 || hasZero === '0') {
          hasZero = true
        }
        if (!hasZero && !hasNaN) {
          sourceData.unshift({
            value: '0',
            label: ' '
          })
        }
      }
      return sourceData
    },
    dealWithData(data) {
      const sourceData = this.autoAddNullValue(data)
      const sourceData_ = _.cloneDeep(sourceData)
      this.options = Array.isArray(sourceData_)
        ? this.tansLate(sourceData_)
        : this.translate_json(sourceData_)
    },
    setDefault() {
      const { value, multiple, ref } = this.configData
      const displayfield = ref && ref.displayfield
      const writebackfield = ref.writebackfield || []
      // 查找一下默认值,如果不存在就设置display_field
      const t = this.options.find(xs => {
        if (xs[value] === this.value && this.value !== undefined) {
          return xs[value] === this.value
        }
      })
      let displayfield_value = ''
      displayfield_value = this.writeBackObject[displayfield]
      if (!t && displayfield_value && displayfield_value !== 'null') {
        // 不存在就设置默认值
        this.value_inner = multiple
          ? displayfield_value.split(',')
          : displayfield_value
      }
      const targetItem = this.options.find(item => item.value === this.value_inner)
      if (targetItem) {
        for (const item of writebackfield) {
          const [key, value] = item.split('=')
          const result = value ? targetItem[value] : targetItem[key]
          if (result !== undefined) {
            this.$set(
              this.writeBackObject,
              key,
              result
            )
          }
        }
      }
    },
    initMockData() {
      this.initMockSelectData(this.elInfo.el)
    },
    // 折线图的模拟数据
    initMockSelectData(type) {
      const mockData_ = mockData[type]
      if (!mockData_) return
      this.editData.config = mockData_.config
      this.editData.sourceData = mockData_.sourceData
      this.options = mockData_.sourceData
    },
    checkUndefinedOrNullOrStr(val) {
      const result = [undefined, null, '']
      return result.includes(val)
    },
    // 复合值转换成2进制
    ten_twe_tans(val) {
      const list = parseInt(val)
        .toString(2)
        .split('')
        .reverse()
      const result = []
      list.forEach((x, index) => {
        if (typeof this.value === 'number') {
          x.toString() === '1' ? result.push(2 ** index) : ''
        } else {
          x.toString() === '1' ? result.push((2 ** index).toString()) : ''
        }
      })
      return result
    },
    // 节流
    remoteMethodsDebounce: _.debounce(async function(query) {
      if (this.is_mock) return
      const data = await this.remoteMethod(query, this.configData)
      this.options = this.tansLate(data || [])
    }, 1000),
    async remoteMethod_(query) {
      await this.remoteMethodsDebounce(query, this.configData)
    },
    clear_select() {
      const { ref, linkBtnUi, cleared, changed } = this.configData
      const { writebackfield } = ref
      if (Array.isArray(writebackfield)) {
        for (const item of writebackfield) {
          const [key] = item.split('=')
          this.$set(this.writeBackObject, key, '')
        }
      }
      if (linkBtnUi) {
        const writeProp = linkBtnUi.writeProp || {}
        for (const key in writeProp) {
          this.$set(this.writeBackObject, key, '')
        }
      }
      this.$emit('input', '')
      this.$emit('clear_callback', '')
      this.$nextTick(() => {
        this.exectAction(cleared)
        this.exectAction(changed)
      })
    },
    select_focus(event) {
      const { remote_condition } = this.configData.ref
      if (remote_condition && !this.is_mock) {
        this.remoteMethod_()
      }
    },
    exectAction(action) {
      const type = typeof action
      if (type === 'function') {
        action(this.value, this.writeBackObject)
      }
    },
    change(val) {
      const is_computed = this.configData.is_computed
      if (is_computed) {
        // 计算模式
        const s = val.reduce((prve, next) => {
          return Number(prve) + Number(next)
        }, 0)
        this.$emit('input', typeof this.value === 'number' ? s : s.toString())
      } else {
        const { multiple, ref } = this.configData
        const { writebackfield } = ref
        if (multiple) {
          const f_list = this.options.filter(xs => val.includes(xs.value))
          if (writebackfield) {
            if (Array.isArray(writebackfield)) {
              for (const item of writebackfield) {
                const [key, value] = item.split('=')
                const r = f_list.map(xs => {
                  return value ? xs[value] : xs[key]
                })
                this.$set(this.writeBackObject, key, r.join())
              }
            } else {
              const f_label = f_list.map(xs => {
                return xs.label
              })
              this.$set(this.writeBackObject, writebackfield, f_label.join())
            }
          }
          this.$emit('input', val.join())
          const return_obj = {
            val,
            data: this.writeBackObject ? this.writeBackObject : {}
          }
          this.$emit('change_callback', return_obj)
        } else {
          // 单选模式
          const target = this.options.find(xs => val === xs.value)

          if (val === '0' || (target && target.label === ' ')) {
            this.$emit('input', '')
            this.value_inner = ''
          }
          if (val && this.configData.allowCreate) {
            this.$emit('input', val)
            this.value_inner = val
          }
          if (writebackfield && target) {
            if (Array.isArray(writebackfield)) {
              for (const item of writebackfield) {
                const [key, value] = item.split('=')
                if (value && !value.startsWith('$')) {
                  const result = value ? target[value] : target[key]
                  if (!value.startsWith('$')) { // 取下拉里面的值
                    if (result !== undefined) {
                      this.$set(
                        this.writeBackObject,
                        key,
                        result
                      )
                    }
                  } else { // 直接设置值
                    const str = val.substr(1, length)
                    this.$set(
                      this.writeBackObject,
                      key,
                      str
                    )
                  }
                }
              }
            } else {
              this.$set(this.writeBackObject, writebackfield, target.label)
            }
          }
          const return_obj = {
            val,
            data: this.writeBackObject ? this.writeBackObject : {}
          }
          if (target.label !== ' ') {
            this.$emit('input', val)
            this.$emit('change_callback', return_obj)
          }
        }
      }

      const changed = this.configData.changed
      this.$nextTick(() => {
        this.exectAction(changed)
      })
      // setTimeout(() => {
      //   this.exectAction(changed)
      // }, 1)
    },
    tansLate(data) {
      const arr = data
      const list = []
      const { value, label } = this.configData
      arr.forEach(element => {
        const parm = {}
        for (const pro in element) {
          if (pro === value && value === label) {
            parm.value = element[pro]
            parm.label = element[pro]
          } else if (pro === value) {
            parm.value = element[pro]
          } else if (pro === label) {
            parm.label = element[label]
          }
          parm[pro] = element[pro]
        }
        list.push(parm)
      })

      return list
    },
    tansLateParm(obj) {
      const { url } = this.configData
      let str
      if (url.includes('/?')) {
        str = '&'
      } else {
        str = '?'
      }
      for (const prop in obj) {
        if (obj[prop]) {
          str += `${prop}=${obj[prop]}&`
        }
      }
      return str === '?' ? '' : str
    },
    translate_json(data = {}) {
      const list = []
      for (const prop in data) {
        const parm = {}
        parm.value = data[prop]
        parm.label = prop
        list.push(parm)
      }
      return list
    },
    initRealUrl() {
      const { url, ref } = this.configData
      const { const_id, table_name, columns, remote_condition } = ref
      if (remote_condition) {
        if (table_name) {
          return `${this.url_dynamic}${table_name}/${columns}/`
        } else {
          return `${this.url_ipCommonAPI}${url}`
        }
      } else {
        if (const_id) {
          return const_id
        } else if (table_name) {
          return `${table_name}/${columns}`
        } else {
          return url
        }
      }
    }
  }
}
</script>

<style scoped>
.contarnBox{
  display: flex;
}
.selectTitle{
  flex:1;
  display: flex;
  justify-content: center;
  align-items: center;
}
.selectCurr{
  flex: 3;
  display: flex;
  justify-content: center;
  align-items: center;
}
.noneStyle >>> .el-input__inner{
  background: inherit;
  border: none;
  color: inherit;
}
.noneStyle >>>.el-input__suffix-inner{
  display: none
}
.noneStyle2 >>> .el-input__inner{
  /* background: inherit;
  border: none;
  color: inherit; */
}
.noneStyle2 >>>.el-input__suffix-inner{
  display: none
}
/* .selectBoxPlus>>> .el-select>.el-input{
    height: 100%;
}
.selectBoxPlus>>>.el-select .el-input__inner{
  height: 100%;
} */
</style>
