<template>
  <div class="tree-node">
    <div 
      class="tree-node-content"
      :style="{ paddingLeft: `${level * 20}px` }"
      :class="{ selected: selectedIds.includes(nodeId) }"
      @click.stop="handleClick"
      @dblclick.stop="handleDblClick"
    >
      <!-- 展开/折叠图标 -->
      <span 
        v-if="hasChildren" 
        class="expand-icon"
        :class="{ expanded }"
        @click.stop="$emit('toggle-expand', nodeId)"
      >
        <img src="@/assets/imgs/arrow-down.svg" :class="{expanded}"/>
      </span>
      <span v-else class="expand-icon-placeholder"></span>
      
      <!-- 复选框 -->
      <input
        type="checkbox"
        :checked="selectedIds.includes(nodeId)"
        @click.stop="handleCheckboxClick"
      />
      
      <!-- 节点标签 -->
      <span class="node-label">{{ nodeLabel }}</span>
    </div>
    
    <!-- 子节点 -->
    <div v-if="hasChildren && expanded" class="tree-node-children">
      <TreeNode
        v-for="child in children"
        :key="getChildId(child)"
        :node="child"
        :level="level + 1"
        :selected-ids="selectedIds"
        :tree-props="treeProps"
        :expanded-keys="expandedKeys"
        :only-leaf-selectable="onlyLeafSelectable"
        @toggle-expand="$emit('toggle-expand', $event)"
        @toggle-select="$emit('toggle-select', $event)"
        @dblclick="$emit('dblclick', $event)"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue';

defineOptions({
  name: 'TreeNode'
});

interface Props {
  node: any;
  level?: number;
  selectedIds: string[];
  treeProps?: {
    children?: string;
    label?: string;
    id?: string;
  };
  expandedKeys: Set<string>;
  onlyLeafSelectable?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  level: 0,
  treeProps: () => ({
    children: 'children',
    label: 'label',
    id: 'id'
  }),
  onlyLeafSelectable: false
});

const emit = defineEmits<{
  'toggle-expand': [nodeId: string];
  'toggle-select': [nodeId: string];
  'dblclick': [nodeId: string];
}>();

const nodeId = computed(() => {
  const idProp = props.treeProps?.id || 'id';
  return String(props.node[idProp] || '');
});

const nodeLabel = computed(() => {
  const labelProp = props.treeProps?.label || 'label';
  return String(props.node[labelProp] || '');
});

const children = computed(() => {
  const childrenProp = props.treeProps?.children || 'children';
  return props.node[childrenProp] || [];
});

const hasChildren = computed(() => children.value && children.value.length > 0);

const expanded = computed(() => props.expandedKeys.has(nodeId.value));

function getChildId(child: any): string {
  const idProp = props.treeProps?.id || 'id';
  return String(child[idProp] || '');
}

function handleClick() {
  // 点击节点主体时切换选中状态
  emit('toggle-select', nodeId.value);
}

function handleCheckboxClick() {
  // 复选框点击事件
  emit('toggle-select', nodeId.value);
}

function handleDblClick() {
  // 双击时触发
  // 如果只允许选择叶子节点，且当前是非叶子节点，则不触发双击
  if (props.onlyLeafSelectable && hasChildren.value) {
    return;
  }
  emit('dblclick', nodeId.value);
}
</script>

<style lang="scss" scoped>
.tree-node {
  user-select: none;
  
  &-content {
    display: flex;
    align-items: center;
    padding: 6px 8px;
    cursor: pointer;
    border-radius: 4px;
    transition: background-color 0.2s;
    
    &:hover {
      background-color: #f5f7fa;
    }
    
    &.selected {
      background-color: #e6f7ff;
    }
    
    .expand-icon {
      display: inline-block;
      width: 16px;
      height: 16px;
      line-height: 16px;
      text-align: center;
      font-size: 10px;
      cursor: pointer;
      transition: transform 0.2s;
      color: #606266;

      img {
        transform: rotate(-90deg);
        &.expanded {
          transform: rotate(0deg);
        }
      }
      
      &:hover {
        color: #409EFF;
      }
    }
    
    .expand-icon-placeholder {
      display: inline-block;
      width: 16px;
    }
    
    input[type="checkbox"] {
      margin: 0 8px;
      cursor: pointer;
    }
    
    .node-label {
      flex: 1;
      font-size: 14px;
      color: #606266;
    }
  }
  
  &-children {
    margin-left: 0;
  }
}
</style>

