<template>
  <el-select-v2
    :style="cssVariables"
    :class="{ 'define-select-v2': attrs.multiple }"
    ref="defineSelectV2Ref"
    v-model="selectedItem"
    :filterable="true"
    :remote="true"
    :remote-method="remoteMethod"
    :options="filteredOptions.options"
    :loading="filteredOptions.loading"
    @change="change"
    @clear="clearReset"
    @visible-change="visibleChange"
  />
</template>

<script lang="ts" setup>
/**
 * 下拉列表搜索组件V2-优化大量下拉列表数据显示的
 */
import { ref, reactive, unref, computed, watch, useAttrs } from "vue";
import { pinyin } from "pinyin-pro";
import { useDebounceFn } from "@vueuse/shared";
import { isArrayLength } from "@/utils/is";

interface ListIitem {
  value: string | number | boolean;
  label: string;
  letter?: string;
}
interface Props {
  options: ListIitem[] | Recordable;
  /**
   * 是否启动加载提示
   */
  isLoading?: boolean;
  /**
   * 防抖时间
   */
  debounceTime?: number;
  /**
   * 默认省略宽度
   */
  leaveOutWidth?: number;
}
// withDefaults ==> 用于辅助defineProps设置默认值
const props = withDefaults(defineProps<Props>(), {
  isLoading: false,
  debounceTime: 500,
  leaveOutWidth: 24,
});
const emit = defineEmits(["update:modelValue", "clickItem", "change"]);
const options = computed(() => props.options);
// 属性穿透属性
const attrs = useAttrs();
// 组件内容数据
const selectedItem = ref();
const filteredOptions = reactive({
  oldOptions: [] as ListIitem[], //用于保存处理的数据源
  options: [] as ListIitem[], //搜索显示的列表数据
  loading: false, //加载
});
const defineSelectV2Ref = ref();
const cssVariables = computed(() => {
    return {
        '--leaveout-width': props.leaveOutWidth + 'px'
    }
})
// 初始化列表数据
watch(
  () => options.value,
  () => {
    if (unref(options).length > 0) {
      filteredOptions.options = unref(options).map((item: ListIitem) => {
        // 中文转拼音字母
        if (!item.letter) {
          // 中文转拼音
          const letter = pinyin(item.label, { toneType: "none" }).replace(
            /\s+/g,
            ""
          );
          item.letter = letter;
        }
        return item;
      });
      filteredOptions.oldOptions = filteredOptions.options;
    } else {
      filteredOptions.options = [];
      filteredOptions.oldOptions = [];
    }
  },
  { immediate: true }
);

// 触发model事件
const change = (val) => {
  emit("update:modelValue", unref(selectedItem));
  emit("change", val);
};
// 重置
const clearReset = () => {
  filteredOptions.options = filteredOptions.oldOptions;
};
// 重置下拉列表数据
const visibleChange = (val) => {
  const currentLength = filteredOptions.options.length;
  const oldLength = filteredOptions.oldOptions.length;
  if (!val && oldLength !== currentLength) {
    filteredOptions.options = filteredOptions.oldOptions;
  }
};
let timer;
// 模糊搜索
const remoteMethod = useDebounceFn((query) => {
  //输入防抖
  clearTimeout(timer);
  if (query) {
    if (!isArrayLength(filteredOptions.oldOptions)) return;
    if (props.isLoading) filteredOptions.loading = true;
    // 匹配对应的列表数据
    const filtered = filteredOptions.oldOptions.filter(
      (item) =>
        item.label.indexOf(query) !== -1 ||
        item.label.toLocaleLowerCase().indexOf(query) !== -1 ||
        item.letter?.startsWith(query)
    );
    // console.log(filtered,":<==过滤的数据");
    filteredOptions.options = filtered;
    props.isLoading && filtered.length > 30
      ? (timer = setTimeout(() => {
          filteredOptions.loading = false;
        }, 500))
      : (filteredOptions.loading = false);
  } else {
    filteredOptions.options = filteredOptions.oldOptions;
  }
}, props.debounceTime);
</script>

<style lang="scss" scoped>
.define-select-v2 {
  :deep(.el-select-v2__tags-text) {
    max-width: var(--leaveout-width) !important;
  }
  :deep(.el-select-v2__input-wrapper) {
    flex: 1 !important;
    margin-left: 8px;
  }
}
</style>
