JVxeSelectDictSearchCell.js 6.78 KB
import debounce from 'lodash/debounce'
import { getAction } from '@/api/manage'
import { cloneObject } from '@/utils/util'
import { filterDictText } from '@/components/dict/JDictSelectUtil'
import { ajaxGetDictItems, getDictItemsFromCache } from '@/api/api'
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'

/** 公共资源 */
const common = {
  /** value - label map,防止重复查询(刷新清空缓存) */
  labelMap: new Map(),

  /** 公共data */
  data() {
    return {
      loading: false,
      innerSelectValue: null,
      innerOptions: [],
    }
  },
  /** 公共计算属性 */
  computed: {
    dict() {
      return this.originColumn.dict
    },
    options() {
      if (this.isAsync) {
        return this.innerOptions
      } else {
        return this.originColumn.options || []
      }
    },
    // 是否是异步模式
    isAsync() {
      let isAsync = this.originColumn.async
      return (isAsync != null && isAsync !== '') ? !!isAsync : true
    },
  },
  /** 公共属性监听 */
  watch: {
    innerValue: {
      immediate: true,
      handler(value) {
        if (value == null || value === '') {
          this.innerSelectValue = null
        } else {
          this.loadDataByValue(value)
        }
      }
    },
    dict() {
      this.loadDataByDict()
    }
  },
  /** 公共方法 */
  methods: {

    // 根据 value 查询数据,用于回显
    async loadDataByValue(value) {
      if (this.isAsync) {
        if (this.innerSelectValue !== value) {
          if (common.labelMap.has(value)) {
            this.innerOptions = cloneObject(common.labelMap.get(value))
          } else {
            let {success, result} = await getAction(`/sys/dict/loadDictItem/${this.dict}`, {key: value})
            if (success && result && result.length > 0) {
              this.innerOptions = [{value: value, text: result[0]}]
              common.labelMap.set(value, cloneObject(this.innerOptions))
            }
          }
        }
      }
      this.innerSelectValue = (value || '').toString()
    },

    // 初始化字典
    async loadDataByDict() {
      if (!this.isAsync) {
        // 如果字典项集合有数据
        if (!this.originColumn.options || this.originColumn.options.length === 0) {
          // 根据字典Code, 初始化字典数组
          let dictStr = ''
          if (this.dict) {
            let arr = this.dict.split(',')
            if (arr[0].indexOf('where') > 0) {
              let tbInfo = arr[0].split('where')
              dictStr = tbInfo[0].trim() + ',' + arr[1] + ',' + arr[2] + ',' + encodeURIComponent(tbInfo[1])
            } else {
              dictStr = this.dict
            }
            if (this.dict.indexOf(',') === -1) {
              //优先从缓存中读取字典配置
              let cache = getDictItemsFromCache(this.dict)
              if (cache) {
                this.innerOptions = cache
                return
              }
            }
            let {success, result} = await ajaxGetDictItems(dictStr, null)
            if (success) {
              this.innerOptions = result
            }
          }
        }
      }
    },

  },

}

// 显示组件,自带翻译
export const DictSearchSpanCell = {
  name: 'JVxeSelectSearchSpanCell',
  mixins: [JVxeCellMixins],
  data() {
    return {
      ...common.data.apply(this),
    }
  },
  computed: {
    ...common.computed,
  },
  watch: {
    ...common.watch,
  },
  methods: {
    ...common.methods,
  },
  render(h) {
    return h('span', {}, [
      filterDictText(this.innerOptions, this.innerSelectValue || this.innerValue)
    ])
  },
}

// 请求id
let requestId = 0

// 输入选择组件
export const DictSearchInputCell = {
  name: 'JVxeSelectSearchInputCell',
  mixins: [JVxeCellMixins],
  data() {
    return {
      ...common.data.apply(this),

      hasRequest: false,
      scopedSlots: {
        notFoundContent: () => {
          if (this.loading) {
            return <a-spin size="small"/>
          } else if (this.hasRequest) {
            return <div>没有查询到任何数据</div>
          } else {
            return <div>{this.tipsContent}</div>
          }
        }
      }
    }
  },
  computed: {
    ...common.computed,
    tipsContent() {
      return this.originColumn.tipsContent || '请输入搜索内容'
    },
    filterOption() {
      if (this.isAsync) {
        return null
      }
      return (input, option) => option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
    },
  },
  watch: {
    ...common.watch,
  },
  created() {
    this.loadData = debounce(this.loadData, 300)//消抖
  },
  methods: {
    ...common.methods,

    loadData(value) {
      const currentRequestId = ++requestId
      this.loading = true
      this.innerOptions = []
      if (value == null || value.trim() === '') {
        this.loading = false
        this.hasRequest = false
        return
      }
      // 字典code格式:table,text,code
      this.hasRequest = true
      getAction(`/sys/dict/loadDict/${this.dict}`, {keyword: value}).then(res => {
        if (currentRequestId !== requestId) {
          return
        }
        let {success, result, message} = res
        if (success) {
          this.innerOptions = result
          result.forEach((item) => {
            common.labelMap.set(item.value, [item])
          })
        } else {
          this.$message.warning(message)
        }
      }).finally(() => {
        this.loading = false
      })
    },

    handleChange(selectedValue) {
      this.innerSelectValue = selectedValue
      this.handleChangeCommon(this.innerSelectValue)
    },
    handleSearch(value) {
      if (this.isAsync) {
        // 在输入时也应该开启加载,因为loadData加了消抖,所以会有800ms的用户主观上认为的卡顿时间
        this.loading = true
        if (this.innerOptions.length > 0) {
          this.innerOptions = []
        }
        this.loadData(value)
      }
    },

    renderOptionItem() {
      let options = []
      this.options.forEach(({value, text, label, title, disabled}) => {
        options.push(
          <a-select-option key={value} value={value} disabled={disabled}>{text || label || title}</a-select-option>
        )
      })
      return options
    },
  },
  render() {
    return (
      <a-select
        showSearch
        allowClear
        value={this.innerSelectValue}
        filterOption={this.filterOption}
        style="width: 100%"
        {...this.cellProps}
        onSearch={this.handleSearch}
        onChange={this.handleChange}
        scopedSlots={this.scopedSlots}
      >
        {this.renderOptionItem()}
      </a-select>
    )
  },
  // 【组件增强】注释详见:JVxeCellMixins.js
  enhanced: {
    aopEvents: {
      editActived(event) {
        dispatchEvent.call(this, event, 'ant-select')
      },
    },
  }
}