<script lang="ts">
import { tableSelectProps, tableSelectEmits } from './props'
import { ElPopover } from 'element-plus'
import type { VxeTableInstance } from 'vxe-table'
export default defineComponent({
  name: 'FsTableSelect',
  props: tableSelectProps,
  emits: tableSelectEmits,
  setup(props, { emit }) {
    // popover 实例
    const popoverRef = ref<InstanceType<typeof ElPopover>>()
    // 表格实例
    const tableRef = ref<VxeTableInstance<any>>()
    // 是否显示
    const visible = ref(false)
    // 选中展示的数据
    const selectLabel = ref<string | Array<any>>('')
    // 加载状态
    const loading = ref(false)
    // 表格数据
    const tableData = ref<any[]>([])
    // 页码
    const pageIndex = ref<number>(1)

    // 是否未选中
    const isEmpty = computed<boolean>(() => {
      if (!props.multiple) {
        return props.modelValue == null || props.modelValue === ''
      }
      return !Array.isArray(props.modelValue) || !props.modelValue.length
    })

    // 是否需要清空图标
    const closeEnable = computed<boolean>(() => {
      return props.clearable && !props.disabled && !isEmpty.value
    })

    onMounted(() => {
      if (props.initValue) {
        initValueChange(props.initValue)
      }
    })

    /* 打开弹窗 */
    const onFocus = (e: FocusEvent) => {
      if (props.automaticDropdown && !visible.value) {
        visible.value = true
      }
      emit('focus', e)
    }

    /* 关闭弹窗 */
    const onBlur = (e: FocusEvent) => {
      emit('blur', e)
    }

    /* 清除事件 */
    const onClear = () => {
      updateModelValue(props.multiple ? [] : null)
      selectLabel.value = ''
      // 取消表格全部选中
      tableRef.value?.clearCheckboxRow()
      emit('clear')
    }

    /* 单个清除事件 */
    const onItemClear = (item: any) => {
      const list = [...(selectLabel.value as Array<any>)]
      const index = list.findIndex(x => x[props.labelKey] === item[props.labelKey])
      list.splice(index, 1)
      selectLabel.value = list

      // 取消表格选中数据
      tableRef.value?.toggleCheckboxRow(item)
      updateModelValue(list.map(x => x[props.valueKey]))
      emit('item-clear', { item, list })
    }

    /* 表格单选事件 */
    const tableRadioChange = (data: any) => {
      selectLabel.value = data.row[props.labelKey]
      visible.value = false
      // 发出选择事件
      updateModelValue(data.row[props.valueKey])
      emit('change', data.row)
    }

    /* 表格多选择事件 */
    const tableCheckboxChange = (data: any) => {
      let result = []
      if (data.checked) {
        // 使用 Set 去重
        const uniqueArray = Array.from(
          new Set([...selectLabel.value, ...data.records].map((x: any) => JSON.stringify(x)))
        ).map((str: any) => JSON.parse(str))
        selectLabel.value = uniqueArray
        result = selectLabel.value.map(x => x[props.valueKey])
      } else {
        const selects = selectLabel.value as Array<any>
        const index = selects.findIndex(x => x[props.valueKey] === data.row[props.valueKey])
        selects?.splice(index, 1)
        result = selects.map(x => x[props.valueKey])
      }
      // 发出选择事件
      updateModelValue(result)
      emit('change', selectLabel.value)
    }

    /* initValue 改变 */
    const initValueChange = (value: any | Array<any>) => {
      if (props.initValue) {
        // 处理回显数据
        if (props.multiple) {
          selectLabel.value = value as Array<any>
        } else {
          selectLabel.value = value[props.labelKey] as any
        }
      }
    }

    /* 分页改变事件 */
    const paginationChange = (data: number) => {
      pageIndex.value = data
      request()
    }

    /* 表格请求完成 */
    const tableDone = () => {
      nextTick(() => {
        const newTableData = tableRef.value?.getTableData().tableData
        newTableData?.forEach(item => {
          if (props.multiple) {
            const temp =
              Array.isArray(selectLabel.value) &&
              selectLabel.value.find(x => x[props.valueKey] === item[props.valueKey])
            temp && tableRef.value?.setCheckboxRow(item, true)
          } else {
            const temp = item[props.valueKey] === props.modelValue
            temp && tableRef.value?.setRadioRow(item)
          }
        })
      })
    }

    /* 请求数据 */
    const request = () => {
      if (typeof props.tableConfig?.datasource === 'function') {
        loading.value = true
        props.tableConfig
          .datasource({
            pageIndex: pageIndex.value,
            pageSize: props.tableConfig.pageSize
          })
          .then((res: any) => {
            tableData.value = res
            tableDone()
          })
          .catch((e: any) => {
            console.warn(e)
          })
          .finally(() => {
            loading.value = false
          })
      } else {
        console.warn('tableConfig.datasource 必须为 Promise')
      }
    }
    request()

    /* 更新选中值 */
    const updateModelValue = (value: any) => {
      emit('update:modelValue', value)
    }

    watch(
      () => props.initValue,
      () => {
        initValueChange(props.initValue as object | Array<any>)
      }
    )

    return {
      popoverRef,
      tableRef,
      selectLabel,
      visible,
      isEmpty,
      loading,
      tableData,
      closeEnable,
      onFocus,
      onBlur,
      onClear,
      onItemClear,
      tableRadioChange,
      tableCheckboxChange,
      paginationChange
    }
  }
})
</script>

<template>
  <el-popover
    ref="popoverRef"
    v-model:visible="visible"
    :placement="placement"
    :width="popperWidth"
    :popper-class="popperClass"
    :popper-options="popperOptions"
    trigger="click"
    transition="el-zoom-in-top"
    teleported
  >
    <template #reference>
      <div class="table-select-container">
        <el-input
          :size="size"
          :disabled="disabled"
          :placeholder="multiple && !isEmpty ? '' : placeholder"
          :readonly="true"
          :validateEvent="false"
          :autocomplete="autocomplete"
          :modelValue="multiple ? '' : selectLabel"
          @focus="onFocus"
          @blur="onBlur"
        >
          <template v-if="$slots.prefix" #prefix>
            <slot name="prefix"></slot>
          </template>
          <template #suffix>
            <div class="select-suffix">
              <ElIcon v-if="closeEnable" class="select-clear" @click.stop="onClear">
                <slot name="clearIcon">
                  <CircleClose />
                </slot>
              </ElIcon>
              <ElIcon class="select-down" :class="{ 'select-down-rotate': visible }">
                <slot name="suffixIcon">
                  <ArrowDown />
                </slot>
              </ElIcon>
            </div>
          </template>
        </el-input>
        <div class="table-select-multiple" v-if="multiple">
          <el-tag
            type="info"
            size="small"
            disable-transitions
            closable
            style="margin-right: 5px"
            v-for="item in selectLabel"
            :key="item[valueKey]"
            @close="onItemClear(item)"
          >
            {{ item[labelKey] }}
          </el-tag>
        </div>
      </div>
    </template>
    <vxe-table
      :data="tableData"
      :row-config="{ isCurrent: true, isHover: true }"
      :radio-config="{ trigger: multiple ? '' : 'row' }"
      :checkbox-config="{ trigger: multiple ? 'row' : '' }"
      ref="tableRef"
      @radio-change="tableRadioChange"
      @checkbox-all="tableCheckboxChange"
      @checkbox-change="tableCheckboxChange"
      v-loading="loading"
    >
      <vxe-column type="checkbox" width="60" v-if="multiple"></vxe-column>
      <vxe-column type="radio" width="40" v-else> </vxe-column>
      <vxe-column v-for="(item, index) in tableConfig?.column" :key="index" v-bind="item">
        <template #default="slotProps" v-if="item.slot">
          <slot :name="item.slot" v-bind="slotProps || {}"></slot>
        </template>
      </vxe-column>
    </vxe-table>
    <div class="table-select-pagination" v-if="tableConfig.total">
      <el-pagination
        background
        layout="total, prev, pager, next, jumper"
        size="small"
        :pager-count="5"
        :page-size="tableConfig.pageSize"
        :total="tableConfig.total"
        @current-change="paginationChange"
      />
    </div>
  </el-popover>
</template>

<style scoped lang="scss">
.table-select-container {
  width: 100%;
  position: relative;
  .select-clear {
    position: absolute;
    right: 10px;
    top: 49%;
    transform: translateY(-50%);
    cursor: pointer;
    border-radius: 50%;
    overflow: hidden;
    z-index: 2;
    color: #fff;
    background-color: var(--el-color-info-light-3);
    opacity: 0;
    &:hover {
      background-color: var(--el-color-info);
    }
  }
  .select-down {
    transition: transform 0.2s;
  }
  .select-down-rotate {
    transform: rotate(180deg);
  }
  &:hover {
    .select-clear {
      opacity: 1;
    }
  }
}
.table-select-multiple {
  position: absolute;
  top: 0px;
  width: calc(100% - 24px);
  height: 100%;
  z-index: 2;
  padding: 4px 10px;
  box-sizing: border-box;
}
.table-select-pagination {
  display: flex;
  justify-content: center;
  margin-top: 12px;
}
</style>
