transfer 穿梭框 小组件

314 阅读1分钟

image.png

<template>
  <div class="transfer">
    <!-- 候选人 -->
    <div class="transfer-panel">
      <p class="transfer-panel__header">
        <el-checkbox
          v-model="candidateChecked"
          @change="candidateCheckChange"
          :indeterminate="candidateIndeterminate"
          >候选人</el-checkbox
        >
      </p>
      <div class="transfer-panel__body">
        <div class="transfer-panel__filter">
          <el-input
            placeholder="请输入关键词搜索"
            prefix-icon="el-icon-search"
            v-model="candidateInput"
            @input="candidateInputHandle"
            clearable
          >
          </el-input>
        </div>
        <div class="transfer-panel__list">
          <div
            class="transfer-panel__item"
            v-for="(item, i) of candidateList"
            :key="i"
            v-show="has_search_word(item.label, 'candidateInput')"
          >
            <el-checkbox
              v-model="item.checked"
              @change="candidateCheckListChange"
              >{{ item.label }}</el-checkbox
            >
          </div>
        </div>
        <p class="transfer-panel__empty" v-show="candidateIsNullOrEmpty">
          {{ candidateTip }}
        </p>
      </div>
    </div>


    <div class="transfer-btns">
      <el-button type="primary" round size="small" @click="recipientPush"
        >收件人<i class="el-icon-arrow-right el-icon--right"></i
      ></el-button>
      <el-button type="primary" round size="small" @click="CcpeoplePush"
        >抄送人<i class="el-icon-arrow-right el-icon--right"></i
      ></el-button>
      <el-button round size="small" icon="el-icon-arrow-left" @click="remove"
        >移除</el-button
      >
    </div>
    <!-- 收件人 -->
    <div class="transfer-panel">
      <p class="transfer-panel__header">
        <el-checkbox
          v-model="recipientChecked"
          @change="recipientCheckChange"
          :indeterminate="recipientIndeterminate"
          >已选收件人</el-checkbox
        >
      </p>
      <div class="transfer-panel__body">
        <div class="transfer-panel__filter">
          <el-input
            placeholder="请输入关键词搜索"
            prefix-icon="el-icon-search"
            v-model="recipientInput"
            @input="recipientInputHandle"
            clearable
          >
          </el-input>
        </div>
        <div class="transfer-panel__list">
          <div
            class="transfer-panel__item"
            v-for="(item, i) of recipientList"
            :key="i"
            v-show="has_search_word(item.label, 'recipientInput')"
          >
            <el-checkbox
              v-model="item.checked"
              @change="recipientCheckListChange"
              >{{ item.label }}</el-checkbox
            >
          </div>
        </div>
        <p class="transfer-panel__empty" v-show="recipientIsNullOrEmpty">
          {{ recipientTip }}
        </p>
      </div>
    </div>
    <!-- 抄送人 -->
    <div class="transfer-panel">
      <p class="transfer-panel__header">
        <el-checkbox
          v-model="CcpeopleChecked"
          @change="CcpeopleCheckChange"
          :indeterminate="CcpeopleIndeterminate"
          >已选收件人</el-checkbox
        >
      </p>
      <div class="transfer-panel__body">
        <div class="transfer-panel__filter">
          <el-input
            placeholder="请输入关键词搜索"
            prefix-icon="el-icon-search"
            v-model="CcpeopleInput"
            @input="CcpeopleInputHandle"
            clearable
          >
          </el-input>
        </div>
        <div class="transfer-panel__list">
          <div
            class="transfer-panel__item"
            v-for="(item, i) of CcpeopleList"
            :key="i"
            v-show="has_search_word(item.label, 'CcpeopleInput')"
          >
            <el-checkbox
              v-model="item.checked"
              @change="CcpeopleCheckListChange"
              >{{ item.label }}</el-checkbox
            >
          </div>
        </div>
        <p class="transfer-panel__empty" v-show="CcpeopleIsNullOrEmpty">
          {{ CcpeopleTip }}
        </p>
      </div>
    </div>
  </div>
</template>

<script>
/* eslint-disable */
export default {
  name: "Transfer",
  watch: {
    candidateList: {
      handler(val) {
        if (val.length == 0) {
          this.candidateChecked = false;
          this.candidateIsNullOrEmpty = true;
          this.candidateTip = "无数据";
        } else {
          this.candidateIsNullOrEmpty = false;
        }
      },
      deep: true,
    },
    recipientList: {
      handler(val) {
        if (val.length == 0) {
          this.recipientChecked = false;
          this.recipientIsNullOrEmpty = true;
          this.recipientTip = "无数据";
        } else {
          this.recipientIsNullOrEmpty = false;
        }
      },
      deep: true,
    },
    CcpeopleList: {
      handler(val) {
        if (val.length == 0) {
          this.CcpeopleChecked = false;
          this.CcpeopleIsNullOrEmpty = true;
          this.CcpeopleTip = "无数据";
        } else {
          this.CcpeopleIsNullOrEmpty = false;
        }
      },
      deep: true,
    },
  },
  data() {
    return {
      candidateChecked: false, // 复选框选中
      candidateIndeterminate: false, // 复选框半选
      candidateTip: "无数据",
      candidateIsNullOrEmpty: false, // 无数据
      candidateInput: "",
      candidateList: [
        {
          id: 1,
          label: "张伟 ZHANGWEI@pingan.com.cn",
          checked: false,
        },
        {
          id: 2,
          label: "张三 ZHANGSAN@pingan.com.cn",
          checked: false,
        },
        {
          id: 3,
          label: "张勇 ZHANGYONG@pingan.com.cn",
          checked: false,
        },
        {
          id: 4,
          label: "张飞 ZHANGFEI@pingan.com.cn",
          checked: false,
        },
        {
          id: 5,
          label: "李武 LIWU@pingan.com.cn",
          checked: false,
        },
        {
          id: 6,
          label: "永华 YONGHUA@pingan.com.cn",
          checked: false,
        },
        {
          id: 7,
          label: "张东 ZHANGDONG@pingan.com.cn",
          checked: false,
        },
        {
          id: 8,
          label: "大勇 DAYONG@pingan.com.cn",
          checked: false,
        },
      ],
      recipientChecked: false, // 复选框选中
      recipientIndeterminate: false, // 复选框半选
      recipientTip: "无数据",
      recipientIsNullOrEmpty: true, // 无数据
      recipientInput: "",
      recipientList: [],
      CcpeopleChecked: false, // 复选框选中
      CcpeopleIndeterminate: false, // 复选框半选
      CcpeopleTip: "无数据",
      CcpeopleIsNullOrEmpty: true, // 无数据
      CcpeopleInput: "",
      CcpeopleList: [],
    };
  },
  methods: {
    candidateCheckChange(e) {
      this.setAllChecked(this.candidateList, e, "candidateIndeterminate");
    },
    recipientCheckChange(e) {
      this.setAllChecked(this.recipientList, e , "recipientIndeterminate");
    },
    CcpeopleCheckChange(e) {
      this.setAllChecked(this.CcpeopleList, e, "CcpeopleIndeterminate");
    },
    // 设置全选状态
    setAllChecked(arr, b, indeterminate) {
      arr.map((item) => {
        item.checked = b;
      });
      if(!b){
        this[indeterminate] = b;
      }
    },
    //   收件人>
    recipientPush() {
      let candidateList = JSON.parse(JSON.stringify(this.candidateList)); // 拷贝原数据, 深拷贝
      candidateList.forEach((item, index) => {
        // 执行 checked 为true 的数据
        if (item.checked) {
          this.recipientList = this.recipientList.concat(item).sort((a, b) => {
            return a.id - b.id;
          }); // 添加到新数据框, 排序
          delete candidateList[index]; // 删除数据
          item.checked = false;
        }
      });
      candidateList = candidateList.filter(function (val) {
        return val;
      }); // 过滤 undefined
      this.candidateList = candidateList; // 更新原数据
      this.setFalse(["candidateIndeterminate"]);
    },
    //   抄送人>
    CcpeoplePush() {
      let candidateList = JSON.parse(JSON.stringify(this.candidateList)); // 拷贝原数据, 深拷贝
      candidateList.forEach((item, index) => {
        // 执行 checked 为true 的数据
        if (item.checked) {
          this.CcpeopleList = this.CcpeopleList.concat(item).sort((a, b) => {
            return a.id - b.id;
          }); // 添加到新数据框, 排序
          delete candidateList[index]; // 删除数据
          item.checked = false;
        }
      });
      candidateList = candidateList.filter(function (val) {
        return val;
      }); // 过滤 undefined
      this.candidateList = candidateList; // 更新原数据
      this.setFalse(["candidateIndeterminate"]);
    },
    // <移除
    remove() {
      let recipientList = JSON.parse(JSON.stringify(this.recipientList)); // 拷贝原数据, 深拷贝
      recipientList.forEach((item, index) => {
        // 执行 checked 为true 的数据
        if (item.checked) {
          this.candidateList = this.candidateList.concat(item).sort((a, b) => {
            return a.id - b.id;
          }); // 添加到新数据框, 排序
          delete recipientList[index]; // 删除数据
          item.checked = false;
        }
      });
      recipientList = recipientList.filter(function (val) {
        return val;
      }); // 过滤 undefined
      this.recipientList = recipientList; // 更新原数据

      let CcpeopleList = JSON.parse(JSON.stringify(this.CcpeopleList)); // 拷贝原数据, 深拷贝
      CcpeopleList.forEach((item, index) => {
        // 执行 checked 为true 的数据
        if (item.checked) {
          this.candidateList = this.candidateList.concat(item).sort((a, b) => {
            return a.id - b.id;
          }); // 添加到新数据框, 排序
          delete CcpeopleList[index]; // 删除数据
          item.checked = false;
        }
      });
      CcpeopleList = CcpeopleList.filter(function (val) {
        return val;
      }); // 过滤 undefined
      this.CcpeopleList = CcpeopleList; // 更新原数据

      this.setFalse(["recipientIndeterminate", "CcpeopleIndeterminate", "recipientChecked", "CcpeopleChecked"]);
    },

    // 候选人列表的复选框事件
    candidateCheckListChange(e) {
      // 半选
      if (this.isIndeterminate(this.candidateList)) {
        this.candidateIndeterminate = true;
      }
      // 全选
      else {
        this.candidateChecked = true;
        this.candidateIndeterminate = false;
      }
    },
    // 收件人列表的复选框事件
    recipientCheckListChange(e) {
      if (this.isIndeterminate(this.recipientList)) {
        this.recipientIndeterminate = true;
      } else {
        this.recipientChecked = true;
        this.recipientIndeterminate = false;
      }
    },
    // 抄送人列表的复选框事件
    CcpeopleCheckListChange(e) {
      if (this.isIndeterminate(this.CcpeopleList)) {
        this.CcpeopleIndeterminate = true;
      } else {
        this.CcpeopleChecked = true;
        this.CcpeopleIndeterminate = false;
      }
    },

    // 判断是否半选
    isIndeterminate(arr) {
      return arr.some((item) => {
        return item.checked == false;
      });
    },

    setFalse(varArr) {
      varArr.map((item) => {
        this[item] = false;
      });
    },

    /**
     * 搜索
     *
     * @param {String} content
     * @param {String} inputVal input框的双向绑定的变量名
     * @param {String} varArr
     *
     */
    has_search_word(content, inputVal) {
      if (this[inputVal]) {
        return content.includes(this[inputVal]);
      }
      return true;
    },

    candidateInputHandle(e) {
      this.dataIsEmpty(this.candidateList, e, "candidate");
    },
    recipientInputHandle(e) {
      this.dataIsEmpty(this.recipientList, e, "recipient");
    },
    CcpeopleInputHandle(e) {
      this.dataIsEmpty(this.CcpeopleList, e, "Ccpeople");
    },

    // 是否显示无匹配数据
    dataIsEmpty(varArr, inputVal, isEmpty) {
      if (!inputVal && varArr.length == 0) {
        this[isEmpty + "IsNullOrEmpty"] = true;
        this[isEmpty + "Tip"] = "无数据"; 
        return;
      } else {
        this[isEmpty + "IsNullOrEmpty"] = !varArr.some((item) => {
          return item.label.indexOf(inputVal) != -1;
        });
        this[isEmpty + "Tip"] = "无匹配数据";
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.transfer {
  width: 100%;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  .transfer-panel {
    border: 1px solid #ebeef5;
    border-radius: 4px;
    overflow: hidden;
    background: #fff;
    display: inline-block;
    vertical-align: middle;
    min-width: 317px;
    max-height: 100%;
    box-sizing: border-box;
    position: relative;
    scrollbar-width: thin;

    .transfer-panel__header {
      height: 40px;
      line-height: 40px;
      background: #f5f7fa;
      margin: 0;
      padding-left: 15px;
      border-bottom: 1px solid #ebeef5;
      box-sizing: border-box;
      color: #000;
    }
    .transfer-panel__body {
      position: relative;
      .transfer-panel__filter {
        text-align: center;
        margin: 15px;
        box-sizing: border-box;
        display: block;
        width: auto;
        font-size: 13px;
      }
      .transfer-panel__list {
        margin: 0;
        padding: 6px 0;
        list-style: none;
        height: 246px;
        overflow: auto;
        box-sizing: border-box;
        .transfer-panel__item {
          height: 30px;
          line-height: 30px;
          padding-left: 15px;
          display: block;
          margin-right: 30px;
          font-size: 14px;
          & + .transfer-panel__item {
            margin-top: 6px;
          }
        }
      }
      .transfer-panel__empty {
        margin: 0;
        height: 30px;
        line-height: 30px;
        padding: 6px 15px 0;
        color: #909399;
        text-align: center;
        font-size: 14px;
        position: absolute;
        left: 50%;
        transform: translate(-50%);
        top: 100px;
      }
    }
    & + .transfer-panel {
      margin-left: 15px;
    }
  }
  /deep/.transfer-btns {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0 20px;
    .el-button + .el-button {
      margin: 10px 0 0 0;
    }
    // .el-button {
    // }
  }
}
</style>