<!-- MultiSelect.vue -->
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';

/* -------------------- 类型 -------------------- */
interface Option {
  label: string;
  value: string | number;
}

/* -------------------- props -------------------- */
const props = withDefaults(
  defineProps<{
    options: Option[];
    modelValue: (string | number)[];
  }>(),
  { options: () => [], modelValue: () => [] }
);

/* -------------------- emit -------------------- */
const emit = defineEmits<{
  'update:modelValue': [val: (string | number)[]];
}>();

/* -------------------- 响应式 -------------------- */
const showDropdown = ref(false);
const root = ref<HTMLElement>();

// 使用计算属性处理双向绑定
const checkedList = computed({
  get: () => props.modelValue,
  set: val => emit('update:modelValue', val)
});

/* -------------------- 计算属性 -------------------- */
const labelMap = computed<Record<string | number, string>>(() =>
  props.options.reduce(
    (acc, cur) => {
      acc[cur.value] = cur.label;
      return acc;
    },
    {} as Record<string | number, string>
  )
);

/* -------------------- 方法 -------------------- */
const toggleDropdown = () => (showDropdown.value = !showDropdown.value);

const isChecked = (val: string | number) => checkedList.value.includes(val);

const toggleCheck = (val: string | number) => {
  const currentList = [...checkedList.value];
  const idx = currentList.indexOf(val);
  if (idx > -1) currentList.splice(idx, 1);
  else currentList.push(val);
  checkedList.value = currentList;
};

/* -------------------- 点外部关闭 -------------------- */
const clickOutSide = (e: Event) => {
  if (root.value && !root.value.contains(e.target as Node)) showDropdown.value = false;
};
onMounted(() => document.addEventListener('click', clickOutSide));
onBeforeUnmount(() => document.removeEventListener('click', clickOutSide));
</script>

<template>
  <div ref="root" class="multi-select">
    <!-- 顶部显示栏 -->
    <div class="display" @click="toggleDropdown">
      <!-- 第一个选中的文字 -->
      <span class="text">{{ checkedList.length ? labelMap[checkedList[0]] : '请选择' }}</span>

      <!-- 右侧小三角 -->
      <span class="arrow" :class="{ open: showDropdown }" />
    </div>

    <!-- 下拉面板 -->
    <Transition name="slide">
      <div v-show="showDropdown" class="dropdown">
        <div
          v-for="item in options"
          :key="item.value"
          class="option"
          :class="{ checked: isChecked(item.value) }"
          @click="toggleCheck(item.value)"
        >
          <span class="label">{{ item.label }}</span>
          <span v-if="isChecked(item.value)" class="right-tick">
            <svg viewBox="0 0 24 24">
              <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" />
            </svg>
          </span>
        </div>
      </div>
    </Transition>
  </div>
</template>

<style scoped>
/* ---------- 变量 ---------- */
.multi-select {
  --border: #dcdfe6;
  --primary: #409eff;
  --bg: #fff;
  --text: #606266;
  --hover: #f5f7fa;
  position: relative;
  display: inline-block;
  width: 160px;
  font-size: 14px;
  color: black;
  user-select: none;
}

/* ---------- 顶部栏 ---------- */
.display {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 32px;
  padding: 0px 15px 0px 10px;
  border-radius: 4px;
  cursor: pointer;
  border: 1px solid #449bd1;
  background-color: #03225596;
}
.display:hover {
  border-color: var(--primary);
}
.text {
  flex: 1;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: #ffffff;
}
.arrow {
  width: 0;
  height: 0;
  margin-left: 8px;
  border: 4px solid transparent;
  border-top-color: white;
  transition: transform 0.2s;
}
.arrow.open {
  transform: rotate(180deg);
}

/* ---------- 下拉面板 ---------- */
.dropdown {
  position: absolute;
  top: 36px;
  left: 0;
  right: 0;
  max-height: 240px;
  border: 1px solid #449bd1;
  background-color: #03225596;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  z-index: 100;
  color: #fff;
}
.option {
  display: flex;
  align-items: center;
  padding: 8px 12px;
  cursor: pointer;
}
.option:hover {
  background: #031c4757;
}
.option.checked {
  color: #11dcfa;
}

/* ---------- 复选框图标 ---------- */
.right-tick {
  margin-left: auto; /* 靠右 */
  width: 20px;
  height: 20px;
  fill: #11dcfa; /* 蓝色对钩 */
}
.right-tick svg {
  display: block;
  width: 100%;
  height: 100%;
}
.check-icon {
  width: 12px;
  height: 12px;
  fill: #fff;
}

/* ---------- 动画 ---------- */
.slide-enter-active,
.slide-leave-active {
  transition: all 0.2s ease;
  transform-origin: center top;
}
.slide-enter-from,
.slide-leave-to {
  transform: scaleY(0.9);
  opacity: 0;
}
</style>
