<script lang="ts" setup>
import { computed } from '@vue/reactivity';
import { ref, watch, PropType } from 'vue';

const props = defineProps({
  // 下拉选项
  options: {
    type: Array as PropType<Array<Record<string, any>>>,
    required: true,
    default: () => []
  },
  // 标题
  name: { type: String, default: '' },
  // 绑定值
  modelValue: { type: Array, default: () => [] },
  // “全部”选项的值
  allValue: { type: [String, Number], default: '' },
  // 自定义label,value
  userKey: {
    type: Object,
    default: () => ({ label: 'label', value: 'value' })
  },
  // 大小
  size: { type: String, default: 'default' },
  // 是否禁用
  disabled: { type: Boolean, default: false },
  allowClear: { type: Boolean, default: true },
  // 是否显式显示（全部），逻辑还是和（全部）的操作一致，只是没有展示”全部“
  showAll: { type: Boolean, default: true },
  placeholder: { type: String, default: '' }
});

const emits = defineEmits(['update:modelValue']);
const selLabel = ref(''); // 已选项的label
const checkedList = ref(props.modelValue); // 已选项
const unCheckList = ref([] as any); // 未选项

const newAddToStr = () => {
  if (checkedList.value?.length) {
    handleChange(false);
  }
};

// 更新已选和未选
const handleChange = (type: boolean) => {
  // true 未选项 => 已选项
  // false  已选项 => 未选项
  if (type) {
    unCheckList.value = changecCardType(unCheckList.value);
    checkedList.value = unCheckList.value;
  } else {
    checkedList.value = changecCardType(checkedList.value);
    unCheckList.value = checkedList.value;
  }
  selLabel.value = toStr();
  toParChange();
};

// 更新值
const toParChange = () => {
  emits('update:modelValue', checkedList.value);
};
// 勾选后  判断是否包含有全部选项，全部选项和其他选项互斥
const changecCardType = (value: any) => {
  if (value.length > 0) {
    const last = value[value.length - 1];
    if (last !== props.allValue) {
      value = value.filter((el: any) => el !== props.allValue);
    } else {
      value = [props.allValue];
    }
  } else {
    value = [props.allValue];
  }
  return value;
};
// 返回中文显示
const toStr = () => {
  let str: string[] = [];
  checkedList.value.forEach((item: any) =>
    props.options.forEach((sub: any) => {
      if (item === sub[props.userKey.value]) str.push(sub[props.userKey.label]);
    })
  );
  return str.join('、');
};

/**
 * options 可能是异步，当 options 数据改变时，调用 newAddToStr 判断 checkedList 是否有数据存在，进行回显操作
 */
watch(
  () => props.options,
  (val: any[]) => {
    if (val?.length) newAddToStr();
  },
  { deep: true }
);

/**
 * v-model 可能是异步，当 modelValue 数据改变时进行监听
 */
watch(
  () => props.modelValue,
  (val: any[]) => {
    if (val?.length) {
      /**
       * ope
       * 根据 props.modelValue 更新相关数据
       */
      const ope = () => {
        checkedList.value = changecCardType(val);
        unCheckList.value = checkedList.value;
        selLabel.value = toStr();
      };
      // 数组中包含“全部”选项，就修改为“全部”选项。判断数组大小，防止死循环
      if (
        val.length !== 1 &&
        val.find(_ => _ === props.allValue) !== undefined
      ) {
        emits('update:modelValue', [props.allValue]);
      } else {
        ope();
      }
    } else {
      // 外部传入的数组不存在任何数据，直接默认“全部”选项
      emits('update:modelValue', [props.allValue]);
    }
  },
  {
    deep: true,
    immediate: true
  }
);

/**
 * 清空，赋值为“全部”
 */
const handleClear = () => {
  emits('update:modelValue', [props.allValue]);
};

const allText1 = computed(() => (props.showAll ? '全部' : ''));
const allText2 = computed(() => (props.showAll ? '(全部)' : ''));

// 为了 UI 视觉好看，showAll=false 的场景下需要判断是否要显示未选中列表
// const showUnCheckList = computed(() => {
//   if (props.showAll) return true;
//   return props.allValue === checkedList.value[0];
// });
const visible = ref(false);
</script>
<script lang="ts">
export default {
  name: 'MultipleSelect'
};
</script>
<template>
  <div class="multiple-select relative" :class="{ disabled }">
    <a-popover
      v-model:visible="visible"
      placement="bottomLeft"
      trigger="click"
      overlayClassName="multiple-select-popover"
    >
      <a-tooltip
        placement="topLeft"
        :title="selLabel || allText1"
        arrow-point-at-center
        color="#fff"
        overlayClassName="multiple-select-tooltip"
      >
        <a-input
          :size="props.size"
          v-model:value="selLabel"
          :placeholder="props.name + allText2 || props.placeholder"
          :disabled="disabled"
          readonly
        >
          <!-- 是否要展示前缀 -->
          <template #prefix v-if="selLabel && props.name !== ''">
            {{ props.name }}&nbsp;&nbsp;
          </template>
          <template #suffix>
            <down-outlined @click="!disabled && (visible = true)" />

            <!-- 不为禁用，开启了清空标志且不为全部 -->
            <div
              v-if="!disabled && allowClear && !checkedList.includes(allValue)"
              class="ant-select-clear"
              @click="handleClear"
            >
              <close-circle-outlined />
            </div>
          </template>
        </a-input>
      </a-tooltip>
      <template #content>
        <div class="chk-box">
          <div class="chk-item-wrap">
            <span class="title">已选择项</span>
            <div class="is-check">
              <a-checkbox-group
                v-model:value="checkedList"
                @change="handleChange(false)"
              >
                <a-row :gutter="[16, 16]">
                  <a-col
                    :span="24"
                    v-show="checkedList.indexOf(props.allValue) !== -1"
                  >
                    <a-checkbox :value="props.allValue" v-if="props.showAll">
                      {{ props.name + '(全部)' }}
                    </a-checkbox>
                    <span v-else class="text-[12px] text-[#999]">(空)</span>

                    <!-- <a-checkbox :value="props.allValue">
                      {{ props.name + '(全部)' }}
                    </a-checkbox> -->
                  </a-col>
                  <template v-for="(item, index) in props.options" :key="index">
                    <a-col
                      :span="24"
                      v-show="
                        checkedList.indexOf(item[props.userKey.value]) !== -1
                      "
                    >
                      <a-checkbox :value="item[props.userKey.value]">
                        {{ item[props.userKey.label] }}
                      </a-checkbox>
                    </a-col>
                  </template>
                </a-row>
              </a-checkbox-group>
            </div>

            <!-- showAll=false 下，checkedList 如果全部都选中，这里就不显示任何 -->
            <!-- <div class="un-check" v-show="showUnCheckList"> -->
            <div class="un-check">
              <a-checkbox-group
                v-model:value="unCheckList"
                @change="handleChange(true)"
              >
                <a-row :gutter="[16, 16]">
                  <a-col
                    v-if="showAll"
                    :span="24"
                    v-show="checkedList.indexOf(props.allValue) === -1"
                  >
                    <a-checkbox :value="props.allValue">
                      {{ props.name + '(全部)' }}
                    </a-checkbox>
                  </a-col>

                  <template
                    v-for="(item, index) in props.options"
                    :key="'c' + index"
                  >
                    <a-col
                      :span="24"
                      v-show="
                        unCheckList.indexOf(item[props.userKey.value]) === -1
                      "
                    >
                      <a-checkbox :value="item[props.userKey.value]">
                        {{ item[props.userKey.label] }}
                      </a-checkbox>
                    </a-col>
                  </template>
                </a-row>
              </a-checkbox-group>
            </div>
          </div>
        </div>
      </template>
    </a-popover>
  </div>
</template>

<style lang="less" scoped>
.multiple-select {
  cursor: pointer;
  &:hover {
    .ant-select-clear {
      opacity: 1;
    }
  }
  &.disabled {
    :deep(.ant-input-prefix),
    :deep(.ant-input-affix-wrapper .ant-input) {
      color: rgba(0, 0, 0, 0.25);
    }
  }
  :deep(.ant-input-prefix) {
    color: #1c2125;
    font-size: 12px;
  }
  :deep(.ant-input-suffix) {
    color: #00000040;
    svg {
      width: 12px;
      height: 12px;
    }
  }
  :deep(.ant-input-affix-wrapper .ant-input) {
    color: #3e8dff;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    width: 100%;
    font-size: 12px;
    cursor: pointer;
  }
}
</style>

<style lang="less">
.multiple-select-popover .ant-popover-inner-content {
  .transition {
    transition: All 0.3s ease-in-out;
    -webkit-transition: All 0.3s ease-in-out;
    -moz-transition: All 0.3s ease-in-out;
    -o-transition: All 0.3s ease-in-out;
  }
  padding: 0;
  .ant-btn {
    margin-bottom: 10px;
  }
  .pop-l {
    width: 160px;
    padding: 20px 4px;
    border-right: 1px solid #ebeff5;
    .ant-col {
      width: 100%;
      height: 30px;
      line-height: 30px;
      color: #2f383f;
      background-color: #fff;
      border-radius: 2px;
      text-align: center;
      cursor: pointer;
      margin-bottom: 10px;
      .transition();
    }
    .ant-radio-wrapper {
      font-size: 12px;
      margin: 0;
    }
    .ant-radio-wrapper span:last-child {
      width: 100%;
      height: 30px;
      line-height: 30px;
    }
    .ant-radio {
      display: none;
    }
    .ant-col:hover {
      background-color: #f4f6f9;
    }
    .on {
      background-color: #f4f6f9;
    }
  }
  .pop-r {
    width: 220px;
    height: 280px;
    margin: 20px 0 40px 0;
    overflow-x: hidden;
    // overflow-y: scroll;
    overflow-y: auto;
    position: relative;
    .ant-col {
      width: 100%;
      height: 34px;
      line-height: 34px;
      color: #2f383f;
      background-color: #fff;
      padding: 0 18px 0 40px;
      text-align: left;
      cursor: pointer;
      .transition();
    }
    .ant-checkbox-wrapper {
      width: 80%;
      font-size: 12px;
    }
    .ant-checkbox-wrapper span:last-child {
      width: 100%;
      height: 34px;
      line-height: 34px;
    }
    .ant-checkbox {
      display: none;
    }
    .ant-col:hover {
      color: #3e8dff;
    }
    .chk-icon {
      width: 12px;
      color: #3e8dff;
      float: right;
      margin-top: 8px;
      display: none;
    }
    .on {
      span {
        color: #3e8dff;
      }
      .chk-icon {
        display: block;
      }
    }
  }
  .submit-wrap {
    text-align: right;
    border-top: 1px solid #ebeff5;
    padding: 10px 10px 0 10px;
  }
  .chk-box {
    max-height: 320px;
    width: 300px;
    padding: 16px 0;
    .chk-item-wrap {
      width: 100%;
      max-height: 288px;
      // overflow-y: scroll;
      overflow-y: auto;
      overflow-x: hidden;
      font-size: 12px;
      .title {
        padding: 0 0 0 16px;
        color: #2f383f;
        display: block;
      }
      .is-check {
        padding: 16px;
        border-bottom: 1px solid #ebeff5;
      }
      .un-check {
        padding: 16px 16px 0 40px;
      }
      .ant-checkbox-wrapper {
        font-size: 12px;
      }
    }
  }
  ::-webkit-scrollbar {
    width: 6px;
    height: 6px;
  }
  ::-webkit-scrollbar-thumb:horizontal,
  ::-webkit-scrollbar-thumb:vertical {
    background-color: #c9cdd6;
    border-radius: 6px;
    -webkit-border-radius: 6px;
  }
}
.multiple-select-tooltip .ant-tooltip-inner {
  color: #252733;
  font-size: 12px;
}
</style>
