DdataeaseShufix: 样式优化
6b3f1a84创建于 4月17日历史提交
<script lang="ts" setup>
import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg'
import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.svg'
import eventBus from '@/utils/eventBus'
import colorFunctions from 'less/lib/less/functions/color.js'
import colorTree from 'less/lib/less/tree/color.js'
import { isISOMobile, isMobile } from '@/utils/utils'
import { cloneDeep } from 'lodash-es'
import { ElMessage } from 'element-plus-secondary'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import QueryConditionConfiguration from './QueryConditionConfiguration.vue'
import type { ComponentInfo } from '@/api/chart'
import { getDynamicRange, getCustomTime } from '@/custom-component/v-query/time-format'
import { getCustomRange } from '@/custom-component/v-query/time-format-dayjs'
import { infoFormat } from './options'
import {
  onBeforeUnmount,
  reactive,
  ref,
  toRefs,
  unref,
  watch,
  computed,
  onMounted,
  onBeforeMount,
  CSSProperties,
  shallowRef,
  provide,
  nextTick
} from 'vue'
import { storeToRefs } from 'pinia'
import { useI18n } from '@/hooks/web/useI18n'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { comInfo } from './com-info'
import { useEmitt } from '@/hooks/web/useEmitt'
import StyleInject from './StyleInject.vue'
import { getKeyList, reRenderAll } from '@/custom-component/v-query/QueryUtils'
const props = defineProps({
  view: {
    type: Object,
    default() {
      return {
        customStyle: ''
      }
    }
  },
  element: {
    type: Object,
    default() {
      return {
        id: null,
        propValue: []
      }
    }
  },
  showPosition: {
    type: String,
    required: true,
    default: ''
  },
  scale: {
    type: Number,
    required: false,
    default: 1
  }
})
const { element, view, scale } = toRefs(props)
const { t } = useI18n()
const vQueryRef = ref()
const dvMainStore = dvMainStoreWithOut()
const { curComponent, canvasViewInfo, mobileInPc, firstLoadMap, editMode } =
  storeToRefs(dvMainStore)
const canEdit = ref(false)
const queryConfig = ref()
const defaultStyle = {
  border: '',
  placeholderSize: 14,
  placeholderShow: true,
  background: '',
  text: '',
  layout: 'horizontal',
  btnList: ['sure'],
  titleLayout: 'left',
  titleShow: false,
  titleColor: '',
  textColorShow: false,
  labelShow: true,
  title: '',
  labelColor: '#1f2329',
  fontSize: '14',
  fontWeight: '',
  fontStyle: '',
  fontSizeBtn: '14',
  fontWeightBtn: '',
  fontStyleBtn: '',
  queryConditionWidth: 227,
  nameboxSpacing: 8,
  queryConditionSpacing: 16,
  queryConditionHeight: 32,
  btnColor: '#3370ff',
  labelColorBtn: '#ffffff'
}
const customStyle = reactive({ ...defaultStyle })
const snapshotStore = snapshotStoreWithOut()
let instanceElMessage = null
let closeTime = null

const closeElMessage = requiredName => {
  if (instanceElMessage) {
    instanceElMessage.close()
  }
  instanceElMessage = ElMessage({
    message: `【${requiredName}】${t('v_query.before_querying')}`,
    type: 'error'
  })

  if (closeTime) {
    clearTimeout(closeTime)
  }
  closeTime = setTimeout(() => {
    instanceElMessage.close()
  }, 2000)
}
const btnStyle = computed(() => {
  const style = {
    color: customStyle.labelColorBtn
  } as CSSProperties
  if (customStyle.fontSizeBtn) {
    style.fontSize = customStyle.fontSizeBtn + 'px'
  }

  if (customStyle.fontWeightBtn) {
    style.fontWeight = customStyle.fontWeightBtn
  }

  if (customStyle.fontStyleBtn) {
    style.fontStyle = customStyle.fontStyleBtn
  }

  return style
})

function rgbaTo16color(color) {
  let val = color
    .replace(/rgba?\(/, '')
    .replace(/\)/, '')
    .replace(/[\s+]/g, '')
    .split(',')
  let a = parseFloat(val[3] || 1),
    r = Math.floor(a * parseInt(val[0]) + (1 - a) * 255),
    g = Math.floor(a * parseInt(val[1]) + (1 - a) * 255),
    b = Math.floor(a * parseInt(val[2]) + (1 - a) * 255)
  return (
    '#' +
    ('0' + r.toString(16)).slice(-2) +
    ('0' + g.toString(16)).slice(-2) +
    ('0' + b.toString(16)).slice(-2)
  )
}

const btnHoverStyle = computed(() => {
  let btnColor = customStyle.btnColor
  if (customStyle.btnColor.startsWith('rgb')) {
    btnColor = rgbaTo16color(customStyle.btnColor)
  }

  if (btnColor.startsWith('#')) {
    btnColor = btnColor.substr(1)
  }

  return {
    rawColor: customStyle.btnColor ?? '#3370ff',
    hoverColor: customStyle.btnColor
      ? colorFunctions
          .mix(new colorTree('ffffff'), new colorTree(btnColor), {
            value: 15
          })
          .toRGB()
      : '#5285FF',
    activeColor: customStyle.btnColor
      ? colorFunctions
          .mix(new colorTree('000000'), new colorTree(btnColor), {
            value: 15
          })
          .toRGB()
      : '#2B5FD9'
  }
})

const btnPrimaryColor = computed(() => {
  return btnHoverStyle.value.rawColor
})

const btnPrimaryHoverColor = computed(() => {
  return btnHoverStyle.value.hoverColor
})

const btnPrimaryActiveColor = computed(() => {
  return btnHoverStyle.value.activeColor
})

const tagColor = computed(() => {
  if (customStyle.background && !customStyle.background.toLowerCase().includes('#ffffff')) {
    return colorFunctions
      .mix(new colorTree('ffffff'), new colorTree(customStyle.background.substr(1)), {
        value: 15
      })
      .toRGB()
  }
  return '#f0f2f5'
})

const btnPlainStyle = computed(() => {
  const style = {
    backgroundColor: 'transparent',
    borderColor: customStyle.btnColor,
    color: customStyle.btnColor
  } as CSSProperties
  if (customStyle.fontSizeBtn) {
    style.fontSize = customStyle.fontSizeBtn + 'px'
  }

  if (customStyle.fontWeightBtn) {
    style.fontWeight = customStyle.fontWeightBtn
  }

  if (customStyle.fontStyleBtn) {
    style.fontStyle = customStyle.fontStyleBtn
  }

  return style
})
const curComponentView = computed(() => {
  return (canvasViewInfo.value[element.value.id] || {}).customStyle
})

const { datasetFieldList } = comInfo()

const setCustomStyle = val => {
  const {
    borderColor,
    btnList,
    titleLayout,
    labelColor,
    text,
    bgColor,
    layout,
    titleShow,
    titleColor,
    title,
    fontSize,
    fontWeight,
    fontStyle,
    fontSizeBtn,
    fontWeightBtn,
    fontStyleBtn,
    queryConditionWidth,
    nameboxSpacing,
    queryConditionSpacing,
    queryConditionHeight,
    labelColorBtn,
    btnColor,
    placeholderSize,
    placeholderShow,
    labelShow
  } = val
  customStyle.background = bgColor || ''
  customStyle.border = borderColor || ''
  customStyle.btnList = [...btnList]
  customStyle.layout = layout
  customStyle.placeholderShow = placeholderShow ?? true
  customStyle.placeholderSize = placeholderSize ?? 14
  nextTick(() => {
    vQueryRef.value.style.setProperty(
      '--ed-component-size',
      `${customStyle.placeholderSize + 18}px`
    )
  })
  customStyle.titleShow = titleShow
  customStyle.titleColor = titleColor
  customStyle.labelColor = labelShow ? labelColor || '' : ''
  customStyle.fontSize = labelShow ? fontSize || '14' : '14'
  customStyle.fontWeight = labelShow ? fontWeight || '' : ''
  customStyle.fontStyle = labelShow ? fontStyle || '' : ''
  customStyle.title = title
  customStyle.text = customStyle.placeholderShow ? text || '' : ''
  customStyle.titleLayout = titleLayout
  customStyle.fontSizeBtn = fontSizeBtn || '14'
  customStyle.fontWeightBtn = fontWeightBtn
  customStyle.fontStyleBtn = fontStyleBtn
  customStyle.queryConditionWidth = queryConditionWidth ?? 227
  customStyle.nameboxSpacing = nameboxSpacing ?? 8
  customStyle.queryConditionSpacing = queryConditionSpacing ?? 16
  customStyle.queryConditionHeight = queryConditionHeight ?? 32
  customStyle.labelColorBtn = labelColorBtn || '#ffffff'
  customStyle.labelShow = labelShow ?? true
  customStyle.btnColor = btnColor || '#3370ff'
  snapshotStore.recordSnapshotCache('setCustomStyle')
}

watch(
  () => view.value,
  val => {
    if (!val?.customStyle?.component) return
    setCustomStyle(val?.customStyle?.component)
  },
  {
    deep: true,
    immediate: true
  }
)

watch(
  () => curComponentView.value,
  val => {
    if (!val?.component) return
    setCustomStyle(val?.component)
  },
  {
    deep: true,
    immediate: true
  }
)
const list = ref([])
let oldList = []
let isResetData = false
watch(
  () => props.element.propValue,
  () => {
    list.value = [...props.element.propValue]
    if (isResetData) {
      isResetData = false
      return
    }
    oldList = cloneDeep(props.element.propValue)
  },
  {
    immediate: true
  }
)
const onComponentClick = () => {
  if (curComponent.value.id !== element.value.id) {
    canEdit.value = false
  }
}

const { emitter } = useEmitt()
const unMountSelect = shallowRef([])
onBeforeMount(() => {
  unMountSelect.value = list.value.map(ele => ele.id)
  ;(props.element.cascade || []).forEach(ele => {
    ele.forEach(item => {
      item.currentSelectValue = item.selectValue
    })
  })
})

const releaseSelect = id => {
  unMountSelect.value = unMountSelect.value.filter(ele => ele !== id)
}

const fillRequireVal = arr => {
  element.value.propValue?.forEach(next => {
    if (arr.some(itx => next.checkedFields.includes(itx)) && next.required) {
      if (next.displayType === '8') {
        const { conditionValueF, conditionValueS, conditionType } = next
        if (conditionType === 0 && conditionValueF === '') {
          next.conditionValueF = next.defaultConditionValueF
        } else {
          if (conditionValueF === '') {
            next.conditionValueF = next.defaultConditionValueF
          }
          if (conditionValueS === '') {
            next.conditionValueS = next.defaultConditionValueS
          }
        }
      } else if (next.displayType === '22') {
        if (next.numValueStart !== 0 && !next.numValueStart) {
          next.numValueStart = next.defaultNumValueStart
        }

        if (next.numValueEnd !== 0 && !next.numValueEnd) {
          next.numValueEnd = next.defaultNumValueEnd
        }
      } else if (
        (Array.isArray(next.selectValue) && !next.selectValue.length) ||
        (next.selectValue !== 0 && !next.selectValue)
      ) {
        if (
          next.optionValueSource === 1 &&
          (next.defaultMapValue?.length || next.displayId) &&
          ![1, 7].includes(+next.displayType)
        ) {
          next.mapValue = next.defaultMapValue
          next.selectValue = next.multiple ? next.defaultMapValue : next.defaultMapValue[0]
        } else {
          next.selectValue = next.defaultValue
        }
      }
    }
  })
}
const queryDataForId = id => {
  let requiredName = ''
  let numName = ''
  const emitterList = (element.value.propValue || [])
    .filter(ele => ele.id === id)
    .reduce((pre, next) => {
      if (next.required) {
        if (!next.defaultValueCheck) {
          requiredName = next.name
        }

        if (next.displayType === '8') {
          const { conditionValueF, conditionValueS, conditionType } = next
          if (conditionType === 0) {
            requiredName = conditionValueF === '' ? next.name : ''
          } else {
            requiredName =
              [conditionValueF || '', conditionValueS || ''].filter(ele => ele !== '').length < 2
                ? next.name
                : ''
          }
        } else if (next.displayType === '22') {
          if (
            (next.numValueStart !== 0 && !next.numValueStart) ||
            (next.numValueEnd !== 0 && !next.numValueEnd)
          ) {
            requiredName = next.name
          }
        } else if (
          (Array.isArray(next.selectValue) && !next.selectValue.length) ||
          (next.selectValue !== 0 && !next.selectValue)
        ) {
          requiredName = next.name
        }
      }

      if (next.displayType === '22') {
        if (
          !isNaN(next.numValueEnd) &&
          !isNaN(next.numValueStart) &&
          next.numValueEnd < next.numValueStart
        ) {
          numName = next.name
        }
        if (
          [next.numValueEnd, next.numValueStart].filter(itx => ![null, undefined, ''].includes(itx))
            .length === 1
        ) {
          requiredName = next.name
        }
      }

      const keyList = getKeyList(next)
      pre = [...new Set([...keyList, ...pre])]
      return pre
    }, [])
  if (!!requiredName) {
    closeElMessage(requiredName)
    return
  }
  if (!!numName) {
    ElMessage.error(`【${numName}】${t('v_query.the_minimum_value')}`)
    return
  }
  if (!emitterList.length) return
  fillRequireVal(emitterList)
  emitterList.forEach(ele => {
    emitter.emit(`query-data-${ele}`)
  })
}
const getQueryConditionWidth = () => {
  return customStyle.queryConditionWidth
}

const getCascadeList = () => {
  const { propValue, cascade = [] } = props.element
  const defaultValueFirstItemMap = propValue.reduce((pre, next) => {
    pre[next.id] = next.defaultValueFirstItem
    return pre
  }, {})
  cascade.forEach(itx => {
    itx.forEach(ele => {
      ele.defaultValueFirstItem = defaultValueFirstItemMap[ele.datasetId.split('--')[1]]
    })
  })
  return cascade
}

const getPlaceholder = computed(() => {
  return {
    placeholderShow: customStyle.placeholderShow
  }
})

const isConfirmSearch = (id, disabledFirstItem = false) => {
  if (componentWithSure.value && !disabledFirstItem) return
  queryDataForId(id)
}

const isConfirmSearchNoRequiredName = id => {
  if (componentWithSure.value) return
  let requiredName = ''
  let numName = ''
  const emitterList = (element.value.propValue || [])
    .filter(ele => ele.id === id)
    .reduce((pre, next) => {
      if (next.displayType === '22') {
        if (
          !isNaN(next.numValueEnd) &&
          !isNaN(next.numValueStart) &&
          next.numValueEnd < next.numValueStart
        ) {
          numName = next.name
        }
        if (
          [next.numValueEnd, next.numValueStart].filter(itx => ![null, undefined, ''].includes(itx))
            .length === 1
        ) {
          requiredName = next.name
        }
      }

      const keyList = getKeyList(next)
      pre = [...new Set([...keyList, ...pre])]
      return pre
    }, [])
  if (!!requiredName) {
    closeElMessage(requiredName)
    return
  }
  if (!!numName) {
    ElMessage.error(`【${numName}】${t('v_query.the_minimum_value')}`)
    return
  }
  if (!emitterList.length) return
  fillRequireVal(emitterList)
  emitterList.forEach(ele => {
    emitter.emit(`query-data-${ele}`)
  })
}

provide('is-confirm-search', isConfirmSearch)
provide('unmount-select', unMountSelect)
provide('release-unmount-select', releaseSelect)
provide('query-data-for-id', queryDataForId)
provide('query-data-for-id-tree', isConfirmSearchNoRequiredName)
provide('com-width', getQueryConditionWidth)
provide('cascade-list', getCascadeList)
provide('placeholder', getPlaceholder)

onBeforeUnmount(() => {
  if (instanceElMessage) {
    instanceElMessage.close()
  }
  if (closeTime) {
    clearTimeout(closeTime)
  }
  emitter.off(`addQueryCriteria${element.value.id}`)
  emitter.off(`editQueryCriteria${element.value.id}`)
  emitter.off(`updateQueryCriteria${element.value.id}`)
  eventBus.off('componentClick', onComponentClick)
})

const updateQueryCriteria = () => {
  if (dvMainStore.mobileInPc && !isMobile()) return
  Array.isArray(element.value.propValue) &&
    element.value.propValue?.forEach(ele => {
      if (ele.auto) {
        const componentInfo = {
          datasetId: ele.dataset.id,
          id: ele.field.id
        }
        const checkedFields = []
        const checkedFieldsMap = {}
        datasetFieldList.value.forEach(ele => {
          if (ele.tableId === componentInfo.datasetId) {
            checkedFields.push(ele.id)
            checkedFieldsMap[ele.id] = componentInfo.id
          }
        })
        ele.checkedFields = checkedFields
        ele.checkedFieldsMap = checkedFieldsMap
      } else {
        if (
          !ele.dataset.id ||
          !!ele.parameters.length ||
          ele.optionValueSource !== 1 ||
          ![0, 2, 5].includes(+ele.displayType)
        )
          return
        const checkedFields = datasetFieldList.value.map(itx => itx.id)
        ele.checkedFields.forEach(itx => {
          if (!checkedFields.includes(itx)) {
            ele.checkedFieldsMap[itx] = ''
          }
        })
        ele.checkedFields = ele.checkedFields.filter(itx => checkedFields.includes(itx))
      }
    })
}

onMounted(() => {
  emitter.on(`addQueryCriteria${element.value.id}`, addCriteriaConfigOut)
  emitter.on(`editQueryCriteria${element.value.id}`, editQueryCriteria)
  emitter.on(`updateQueryCriteria${element.value.id}`, updateQueryCriteria)
  updateQueryCriteria()

  if (dvMainStore.mobileInPc && !isMobile()) {
    queryData()
  }
})

const dragover = () => {
  // do
}

const drop = e => {
  const componentInfoArr: ComponentInfo[] = JSON.parse(e.dataTransfer.getData('dimension') || '{}')
  componentInfoArr.forEach(componentInfo => {
    const checkedFields = []
    const checkedFieldsMap = {}
    datasetFieldList.value.forEach(ele => {
      if (ele.tableId === componentInfo.datasetId) {
        checkedFields.push(ele.id)
        checkedFieldsMap[ele.id] = componentInfo.id
      }
    })
    // URL 字段类型换成文本字段类型
    const displayType = componentInfo.deType === 7 ? 0 : `${componentInfo.deType}`
    list.value.push({
      ...infoFormat(componentInfo),
      auto: true,
      optionValueSource: 1,
      checkedFields,
      checkedFieldsMap,
      displayType
    })
  })
  element.value.propValue = [...list.value]
  snapshotStore.recordSnapshotCache('drop')
}

const editeQueryConfig = (queryId: string) => {
  queryConfig.value.setCondition(queryId)
}

const editQueryCriteria = () => {
  if (!list.value.length) {
    addCriteriaConfigOut()
    return
  }
  editeQueryConfig(list.value[0].id)
}

const addCriteriaConfigOut = () => {
  queryConfig.value.setConditionOut()
}

const delQueryConfig = index => {
  const com = cloneDeep(unref(list))
  list.value.splice(index, 1)
  element.value.propValue = [...list.value]
  snapshotStore.recordSnapshotCache('delQueryConfig')
  reRenderAll(com, cloneDeep(unref(list)))
}

const resetData = () => {
  isResetData = true
  element.value.propValue = []
  nextTick(() => {
    element.value.propValue = cloneDeep(oldList)
    ;(element.value.propValue || []).reduce((pre, next) => {
      next.conditionValueF = next.defaultConditionValueF
      next.conditionValueOperatorF = next.defaultConditionValueOperatorF
      next.conditionValueS = next.defaultConditionValueS
      next.conditionValueOperatorS = next.defaultConditionValueOperatorS

      if (next.displayType === '22') {
        next.numValueEnd = next.defaultNumValueEnd
        next.numValueStart = next.defaultNumValueStart
      }

      if (!next.defaultValueCheck) {
        next.defaultValue = next.multiple || +next.displayType === 7 ? [] : undefined
      }
      next.selectValue = Array.isArray(next.defaultValue)
        ? [...next.defaultValue]
        : next.defaultValue
      if (next.optionValueSource === 1 && next.defaultMapValue?.length) {
        next.mapValue = Array.isArray(next.defaultMapValue)
          ? [...next.defaultMapValue]
          : next.defaultMapValue
      }

      if (
        next.defaultValueCheck &&
        [1, 7].includes(+next.displayType) &&
        next.timeType === 'dynamic'
      ) {
        if (+next.displayType === 1) {
          let selectValue = getDynamicRange(next) || []
          next.defaultValue = new Date(selectValue[0])
          next.selectValue = new Date(selectValue[0])
        } else {
          const {
            timeNum,
            relativeToCurrentType,
            around,
            relativeToCurrentRange,
            arbitraryTime,
            timeGranularity,
            timeNumRange,
            relativeToCurrentTypeRange,
            aroundRange,
            timeGranularityMultiple,
            arbitraryTimeRange
          } = next

          let startTime = getCustomTime(
            timeNum,
            relativeToCurrentType,
            timeGranularity,
            around,
            arbitraryTime,
            timeGranularityMultiple,
            'start-panel'
          )
          let endTime = getCustomTime(
            timeNumRange,
            relativeToCurrentTypeRange,
            timeGranularity,
            aroundRange,
            arbitraryTimeRange,
            timeGranularityMultiple,
            'end-panel'
          )

          if (!!relativeToCurrentRange && relativeToCurrentRange !== 'custom') {
            ;[startTime, endTime] = getCustomRange(relativeToCurrentRange)
          }
          next.defaultValue = [startTime, endTime]
          next.selectValue = [startTime, endTime]
        }
      }

      ;(props.element.cascade || []).forEach(ele => {
        ele.forEach(item => {
          const comId = item.datasetId.split('--')[1]
          if (next.id === comId) {
            item.currentSelectValue = Array.isArray(next.selectValue)
              ? next.selectValue
              : [next.selectValue].filter(itx => ![null, undefined].includes(itx))
            useEmitt().emitter.emit(`${item.datasetId.split('--')[1]}-select`)
          }
        })
      })
      const keyList = getKeyList(next)
      pre = [...new Set([...keyList, ...pre])]
      return pre
    }, [])
    !componentWithSure.value && queryData()
  })
}

const clearData = () => {
  ;(props.element.cascade || []).forEach(ele => {
    ele.forEach(item => {
      if (item.currentSelectValue?.length) {
        useEmitt().emitter.emit(`${item.datasetId.split('--')[1]}-select`)
        item.currentSelectValue = []
      }
    })
  })
  ;(list.value || []).reduce((pre, next) => {
    if (!next.visible) {
      return pre
    }
    next.selectValue = next.multiple || +next.displayType === 7 ? [] : undefined
    if (next.optionValueSource === 1 && next.defaultMapValue?.length) {
      next.mapValue = next.multiple ? [] : undefined
    }
    next.conditionValueF = ''
    next.conditionValueS = ''

    if (next.displayType === '22') {
      next.numValueEnd = undefined
      next.numValueStart = undefined
    }
    const keyList = getKeyList(next)
    pre = [...new Set([...keyList, ...pre])]
    return pre
  }, [])
  !componentWithSure.value && queryData()
}
const listVisible = computed(() => {
  return list.value.filter(itx => itx.visible)
})

const componentWithSure = computed(() => {
  return customStyle.btnList.includes('sure')
})

watch(
  () => componentWithSure.value,
  (val, oldVal) => {
    if (!val && oldVal) {
      queryData()
    }
  },
  {
    immediate: false
  }
)

const boxWidth = computed(() => {
  return `${customStyle.placeholderSize}px`
})

const boxHeight = computed(() => {
  return `${customStyle.queryConditionHeight || 32}px`
})

const queryData = () => {
  let requiredName = ''
  let numName = ''
  const emitterList = (element.value.propValue || []).reduce((pre, next) => {
    if (next.required) {
      if (!next.defaultValueCheck) {
        requiredName = next.name
      }

      if (next.displayType === '8') {
        const { conditionValueF, conditionValueS, conditionType } = next
        if (conditionType === 0) {
          requiredName = conditionValueF === '' ? next.name : ''
        } else {
          requiredName =
            [conditionValueF || '', conditionValueS || ''].filter(ele => ele !== '').length < 2
              ? next.name
              : ''
        }
      } else if (next.displayType === '22') {
        if (
          (next.numValueEnd !== 0 && !next.numValueEnd) ||
          (next.numValueStart !== 0 && !next.numValueStart)
        ) {
          requiredName = next.name
        }
      } else if (
        (Array.isArray(next.selectValue) && !next.selectValue.length) ||
        (next.selectValue !== 0 && !next.selectValue)
      ) {
        requiredName = next.name
      }
    }

    if (next.displayType === '22') {
      if (
        !isNaN(next.numValueEnd) &&
        !isNaN(next.numValueStart) &&
        next.numValueEnd < next.numValueStart
      ) {
        numName = next.name
      }
      if (
        [next.numValueEnd, next.numValueStart].filter(itx => ![null, undefined, ''].includes(itx))
          .length === 1
      ) {
        requiredName = next.name
      }
    }
    const keyList = getKeyList(next)
    pre = [...new Set([...keyList, ...pre])]
    return pre
  }, [])
  if (!!requiredName) {
    closeElMessage(requiredName)
    return
  }

  if (!!numName) {
    ElMessage.error(`【${numName}】${t('v_query.the_minimum_value')}`)
    return
  }
  if (!emitterList.length) return
  if (!(dvMainStore.mobileInPc && !isMobile())) {
    dvMainStore.setFirstLoadMap([...new Set([...emitterList, ...firstLoadMap.value])])
  }
  emitterList.forEach(ele => {
    emitter.emit(`query-data-${ele}`)
  })
}
const titleStyle = computed(() => {
  return {
    textAlign: customStyle.titleLayout || 'left',
    color: customStyle.titleColor || '#1f2329'
  } as CSSProperties
})

const labelStyle = computed(() => {
  const style = {
    fontSize: customStyle.fontSize + 'px',
    lineHeight: +customStyle.fontSize + 8 + 'px'
  } as CSSProperties
  if (customStyle.fontWeight) {
    style.fontWeight = customStyle.fontWeight
  }

  if (customStyle.fontStyle) {
    style.fontStyle = customStyle.fontStyle
  }

  if (customStyle.labelColor) {
    style.color = customStyle.labelColor
  }
  return style
})

const comLayout = computed(() => {
  return customStyle.labelShow ? customStyle.layout : 'horizontal'
})

const paddingTop = computed<CSSProperties>(() => {
  return {
    paddingTop: comLayout.value !== 'horizontal' ? customStyle.nameboxSpacing + 22 + 'px' : '0'
  }
})

const marginRight = computed<CSSProperties>(() => {
  return {
    marginRight: comLayout.value === 'horizontal' ? customStyle.nameboxSpacing + 'px' : '8px'
  }
})

const autoStyle = computed(() => {
  if (isISOMobile()) {
    return {
      position: 'absolute',
      height: 100 / scale.value + '%!important',
      width: 100 / scale.value + '%!important',
      left: 50 * (1 - 1 / scale.value) + '%', // 放大余量 除以 2
      top: 50 * (1 - 1 / scale.value) + '%', // 放大余量 除以 2
      transform: 'scale(' + scale.value + ') translateZ(0)'
    } as CSSProperties
  } else {
    return { zoom: scale.value }
  }
})
</script>

<template>
  <div class="v-query-container" ref="vQueryRef" :style="autoStyle" @keydown.stop @keyup.stop>
    <p v-if="customStyle.titleShow" class="title" :style="titleStyle">
      {{ customStyle.title }}
    </p>
    <div
      :class="['v-query', comLayout, customStyle.titleShow && !!customStyle.title && 'title-show']"
      @dragover.prevent.stop="dragover"
      @drop.prevent.stop="drop"
    >
      <div v-if="!listVisible.length" class="no-list-label flex-align-center">
        <div class="container flex-align-center">
          {{ t('v_query.here_or_click') }}
          <el-button
            :disabled="showPosition === 'preview' || mobileInPc"
            @click="addCriteriaConfigOut"
            style="font-family: inherit"
            text
          >
            {{ t('v_query.add_query_condition') }}
          </el-button>
        </div>
      </div>
      <div class="query-fields-container">
        <div
          class="query-item"
          :style="{ marginRight: `${customStyle.queryConditionSpacing}px` }"
          :key="ele.id"
          v-for="(ele, index) in listVisible"
        >
          <div class="query-field" :style="paddingTop">
            <div class="label" :style="marginRight">
              <div class="label-wrapper" v-show="customStyle.labelShow">
                <div class="label-wrapper-text" :style="labelStyle">
                  <el-tooltip
                    popper-class="label-wrapper-text_tooltip"
                    effect="dark"
                    :content="ele.name"
                    :show-arrow="false"
                    placement="top-start"
                  >
                    {{ ele.name }}
                  </el-tooltip>
                </div>
                <span v-if="ele.required" class="required">*</span>
              </div>
              <div
                class="label-wrapper-tooltip"
                v-if="
                  !['preview', 'edit-preview'].includes(showPosition) &&
                  !dvMainStore.mobileInPc &&
                  editMode === 'edit'
                "
              >
                <el-tooltip
                  effect="dark"
                  :content="t('v_query.set_filter_condition')"
                  placement="top"
                >
                  <el-icon @click="editeQueryConfig(ele.id)">
                    <Icon name="icon_edit_outlined"><icon_edit_outlined class="svg-icon" /></Icon>
                  </el-icon>
                </el-tooltip>
                <el-tooltip effect="dark" :content="t('v_query.delete_condition')" placement="top">
                  <el-icon style="margin-left: 8px" @click="delQueryConfig(index)">
                    <Icon name="icon_delete-trash_outlined"
                      ><icon_deleteTrash_outlined class="svg-icon"
                    /></Icon>
                  </el-icon>
                </el-tooltip>
              </div>
            </div>
            <div class="query-select">
              <StyleInject
                v-if="customStyle.queryConditionWidth !== 0"
                :customStyle="customStyle"
                :config="ele"
              ></StyleInject>
            </div>
          </div>
        </div>
        <div class="query-button" v-if="!!listVisible.length">
          <el-button
            @click.stop="clearData"
            :style="btnPlainStyle"
            v-if="customStyle.btnList.includes('clear')"
            plain
          >
            {{ t('commons.clear') }}
          </el-button>
          <el-button
            @click.stop="resetData"
            :style="btnPlainStyle"
            v-if="customStyle.btnList.includes('reset')"
            plain
          >
            {{ t('chart.reset') }}
          </el-button>
          <el-button
            @click.stop="queryData"
            style="margin-right: 7px"
            :style="btnStyle"
            v-if="componentWithSure"
            type="primary"
          >
            {{ t('commons.adv_search.search') }}
          </el-button>
        </div>
      </div>
    </div>
  </div>
  <Teleport to="body">
    <QueryConditionConfiguration
      :query-element="element"
      @queryData="queryData"
      ref="queryConfig"
      @reRenderAll="reRenderAll"
    ></QueryConditionConfiguration>
  </Teleport>
</template>

<style lang="less" scoped>
.v-query-container {
  width: 100%;
  height: 100%;
  overflow: auto;
  position: relative;
  --ed-font-size-base: v-bind(boxWidth);

  :deep(.ed-select-v2 .ed-select-v2__selection .ed-tag),
  :deep(.select-trigger .ed-select__tags .ed-tag) {
    background-color: v-bind(tagColor);
  }

  :deep(.ed-input),
  :deep(.ed-date-editor) {
    --ed-input-height: v-bind(boxHeight);
  }

  :deep(.ed-select__wrapper),
  :deep(.text-search-select .ed-input__wrapper),
  :deep(.text-search-select .ed-select__wrapper) {
    height: v-bind(boxHeight);
  }

  .ed-button--primary {
    --ed-button-bg-color: v-bind(btnHoverStyle.rawColor);
    --ed-button-border-color: v-bind(btnHoverStyle.rawColor);
    --ed-button-hover-border-color: v-bind(btnHoverStyle.hoverColor);
    --ed-button-hover-bg-color: v-bind(btnHoverStyle.hoverColor);
    background-color: v-bind(btnPrimaryColor);
  }

  .ed-button--primary.ed-button--primary.ed-button--primary:hover,
  .ed-button--primary.ed-button--primary.ed-button--primary:focus {
    background-color: v-bind(btnPrimaryHoverColor);
  }

  .ed-button--primary.ed-button--primary.ed-button--primary:active {
    background-color: v-bind(btnPrimaryActiveColor);
    border-color: v-bind(btnPrimaryHoverColor);
  }

  :deep(.ed-tag) {
    --ed-tag-font-size: v-bind(boxWidth);
  }

  :deep(.ed-select-v2),
  :deep(.ed-select__wrapper) {
    font-size: v-bind(boxWidth);
  }

  .no-list-label {
    width: 100%;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 0;
    .container {
      width: 100%;
      justify-content: center;
      color: #646a73;
      text-align: center;
      font-size: 16px;
      font-style: normal;
      font-weight: 400;
      line-height: 24px;
      .ed-button {
        font-size: 16px;
        font-style: normal;
        font-weight: 400;
        line-height: 24px;
      }
    }
  }
  .title {
    color: #1f2329;
    font-feature-settings: 'clig' off, 'liga' off;
    font-size: 14px;
    font-style: normal;
    font-weight: 500;
    line-height: 22px;
    letter-spacing: -0.1px;
  }
}
.v-query {
  width: 100%;
  height: 100%;
  line-height: 1.5;
  color: rgba(0, 0, 0, 0.87);
  align-items: center;
  position: relative;
  display: flex;
  margin: auto 0;
  padding: 16px 4px 4px 4px;
  .query-fields-container {
    display: flex;
    flex-wrap: wrap;
    width: 100%;
    height: 100%;
  }
  .query-item {
    position: relative;
    line-height: 28px;
    margin: 5px 16px 5px 0;
    max-width: 100%;
    min-width: 60px;
    .query-field {
      position: relative;
      .label {
        display: flex;
        overflow: hidden;
        color: #1f2329;

        .label-wrapper {
          visibility: visible;
          pointer-events: auto;
          cursor: auto;
          line-height: 16px;
          color: #575757;
          box-sizing: border-box;
          margin: 0;
          padding: 0;
          display: flex;
          flex: 1 1 0;
          overflow: hidden;
        }
        .label-wrapper-text {
          position: relative;
          cursor: pointer;
          flex: 0 1 auto;
          max-width: 100%;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
          color: #1f2329;
          font-size: 14px;
          font-style: normal;
          font-weight: 400;
          line-height: 22px;
        }

        .required {
          font-size: 14px;
          color: #f54a45;
          margin-left: 3px;
          line-height: 22px;
        }
        .label-wrapper-tooltip {
          align-items: center;
          background: #fff;
          border-radius: 2px;
          font-size: 16px;
          display: none;
          flex: 0 0 auto;
          height: 16px;
          line-height: 16px;
          color: #575757;
          white-space: nowrap;
        }
      }

      .query-select {
        display: flex;
        flex-wrap: wrap;
        line-height: 28px;
        position: relative;

        :deep(.ed-date-editor) {
          .ed-input__wrapper {
            width: 100%;
          }
        }
      }
    }
  }
  .query-button {
    align-self: flex-end;
    line-height: 40px;
    margin: auto 0 5px auto;
    z-index: 0;
  }

  &.title-show {
    height: calc(100% - 22px);
  }

  &.vertical {
    .query-fields-container {
      .query-field {
        padding-top: 30px;

        &:hover {
          .label-wrapper-tooltip {
            display: inline-flex !important;
            cursor: pointer;
            padding: 4px 8px;
            height: 26px;
            width: 58px;
            border-radius: 6px;
            border: 1px solid #dee0e3;
            background: #fff;
            box-shadow: 0px 4px 8px 0px rgba(31, 35, 41, 0.1);
          }
        }
        .label {
          align-items: center;
          height: 16px;
          left: 0;
          line-height: 16px;
          max-width: 100%;
          position: absolute;
          right: 0;
          top: 0;
          overflow: visible;
        }
      }
    }
  }

  &.horizontal {
    line-height: 1.5;
    color: rgba(0, 0, 0, 0.87);
    align-items: center;
    display: flex;
    margin: auto 0;
    .query-fields-container {
      align-items: flex-start;

      .query-field {
        align-items: center;
        display: flex;
        .label {
          visibility: visible;
          pointer-events: auto;
          cursor: auto;
          line-height: 28px;
          box-sizing: border-box;
          flex: 0 0 auto;
          margin-right: 8px;

          .label-wrapper {
            max-width: 200px;
          }
          .label-wrapper-tooltip {
            position: absolute;
            right: 0;
            top: -21px;
            z-index: 11;
            padding: 4px 8px;
            height: 26px;
            width: 58px;
            border-radius: 6px;
            border: 1px solid #dee0e3;
            background: #fff;
            box-shadow: 0px 4px 8px 0px rgba(31, 35, 41, 0.1);
          }
        }
        &:hover {
          .label-wrapper-tooltip {
            display: block;
            cursor: pointer;
          }
        }
      }
    }
  }
}
</style>
<style lang="less">
.label-wrapper-text_tooltip {
  max-width: 200px;
  white-space: wrap;
}
.load-select {
  .ed-select-dropdown__list {
    & > div {
      &:nth-child(1) {
        .ed-radio__inner::after {
          display: none !important;
        }
      }
    }
  }
  .ed-select-dropdown {
    &:nth-child(1) {
      .ed-checkbox__inner::after {
        display: none !important;
      }
    }
  }
}
</style>