• 徐俊's avatar
    xujun · 7005264d
    徐俊 authored
    7005264d
selectItem.vue 6.22 KB
<template>
  <div class="select-item">
    <div class="select-checked">
      <a-checkbox :indeterminate="indeterminate" :checked="checkAll" @change="onCheckAllChange" /> <span>{{nowSelectKeys.length}}</span>
    </div>
    <div class="select-content">
      <ul class="data-list-content">
        <li v-for="(item, index) in dataList" :key="item.key || 'item-' + index" @click="onChange(item,index)" class="data-list-content-item">
          <input type="checkbox" class="list-checkbox-input" :checked="item.selected">
          <span style="font-size:8pt;" :title="item.description" :class="{'font-red':item.disabled}">
            <span>{{item.title}}<span style="font-style: italic;color: #8e99a5;" :class="{'font-red':item.disabled}">({{item.description}})</span></span>
          </span>
        </li>
      </ul>
    </div>
  </div>
</template>
<script>
export default {
  name: 'selectItem',
  components: {

  },
  data () {
    return {
      selectKeys: [],
      nowSelectKeys: [],
      indeterminate: false,
      checkAll: false,
    }
  },
  props: {
    value: {
      type: Array,
      default: () => {
        return []
      }
    },
    dataList: {
      type: Array,
      default: () => {
        return []
      }
    },
  },
  created () {
    this.selectKeys = this.value
    this.initData()
  },
  methods: {
    getStyle (value) {
      return {
        color: value ? 'red' : 'black'
      };
    },
    onChange (e) {
      if (!e || typeof e !== 'object') {
        console.warn('尝试操作不存在的元素');
        return;
      }
      
      e.selected = !e.selected
      if (e.selected) {
        this.selectKeys.push(e)
      } else {
        for (let j = 0; j < this.selectKeys.length; j++) {
          if (e.key && e.key === this.selectKeys[j].key) {
            this.selectKeys.splice(j, 1)
            break
          }
        }
      }
      this.initData()
      this.$emit("input", this.selectKeys)
    },
    onCheckAllChange (e) {
      if (e.target.checked) {
        for (let i = 0; i < this.dataList.length; i++) {
          if (!this.dataList[i]) continue;
          
          this.dataList[i].selected = e.target.checked
          let state = false;
          for (let j = 0; j < this.selectKeys.length; j++) {
            if (this.dataList[i].key && this.selectKeys[j] && this.dataList[i].key === this.selectKeys[j].key) {
              state = true
              break
            }
          }
          if (!state) {
            this.selectKeys.push(this.dataList[i])
          }
        }
      }
      else {
        for (let i = 0; i < this.dataList.length; i++) {
          if (!this.dataList[i]) continue;
          
          this.dataList[i].selected = e.target.checked
          for (let j = 0; j < this.selectKeys.length; j++) {
            if (this.selectKeys[j] && this.dataList[i].key && this.dataList[i].key === this.selectKeys[j].key) {
              this.selectKeys.splice(j, 1);
              break;
            }
          }
        }
      }
      this.initData()
      this.$emit("input", this.selectKeys)
    },
    initData () {
      this.nowSelectKeys = []
      for (let i = 0; i < this.dataList.length; i++) {
        if (this.dataList[i] && this.dataList[i].selected) {
          this.nowSelectKeys.push(this.dataList[i])
        }
      }
      this.indeterminate = !!this.nowSelectKeys.length && this.nowSelectKeys.length < this.dataList.length
      this.checkAll = this.nowSelectKeys.length === this.dataList.length && this.nowSelectKeys.length > 0
    },
    ensureUniqueKeys() {
      if (!Array.isArray(this.dataList)) {
        console.warn('dataList 不是数组');
        return;
      }
      
      const keyMap = new Map();
      let hasDuplicates = false;
      
      const validDataList = this.dataList.filter(item => item && typeof item === 'object');
      
      validDataList.forEach((item, index) => {
        if (!item.key) {
          item.key = 'generated-' + Date.now() + '-' + index;
        } else if (keyMap.has(item.key)) {
          console.warn(`发现重复键: ${item.key},已自动修复`);
          item.key = item.key + '-' + Date.now() + '-' + index;
          hasDuplicates = true;
        }
        keyMap.set(item.key, true);
      });
      
      if (hasDuplicates) {
        this.initData();
      }
    },
    cleanupSelectKeys() {
      if (!Array.isArray(this.selectKeys)) return;
      
      const validKeys = new Set();
      this.dataList.forEach(item => {
        if (item && item.key) validKeys.add(item.key);
      });
      
      this.selectKeys = this.selectKeys.filter(item => {
        return item && item.key && validKeys.has(item.key);
      });
    }
  },
  watch: {
    dataList: {
      handler(dataList) {
        this.ensureUniqueKeys();
        this.cleanupSelectKeys();
        this.initData();
      },
      immediate: true
    },
    value: {
      handler(val) {
        if (Array.isArray(val)) {
          this.selectKeys = val;
          this.cleanupSelectKeys();
          this.initData();
        }
      },
      immediate: true
    }
  }
}
</script>
 <style scoped lang="less">
.font-red {
  color: red !important;
}
.select-item {
  position: relative;
  width: 100%;
  height: 100%;
  vertical-align: middle;
  border-radius: 4px;
  .select-checked {
    width: 100%;
    height: 40px;
    padding: 8px 5px 9px;
    overflow: hidden;
    color: rgba(0, 0, 0, 0.65);
    background: #fff;
    border-bottom: 1px solid #e8e8e8;
    border-radius: 4px 4px 0 0;
  }
  .select-content {
    width: 100%;
    height: calc(100% - 40px);
    overflow-x: hidden;
    overflow-y: auto;
    ul {
      height: 100%;
      margin: 0;
      padding: 0;
      overflow: auto;
      list-style: none;
    }
    ul li {
      height: 24px;
      padding: 0px 4px;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
      transition: all 0.3s;
      overflow: hidden;
      cursor: pointer;
    }
    ul li:hover {
      background-color: rgb(230 247 255);
    }
    ul li > span {
      padding-left: 4px;
      cursor: pointer;
      margin: 0;
      vertical-align: middle;
    }
    ul li input {
      display: inline-block;
      vertical-align: middle;
    }
    .list-checkbox-input {
      width: 14px;
      height: 14px;
      cursor: pointer;
    }
  }
}
</style>