vue中sortablejs处理拖拽,过滤input之后需要重新聚焦

322 阅读6分钟

1、官方文档:www.sortablejs.com/options.htm…

sortablejs.github.io/Sortable/#s…

github.com/SortableJS/…

github.com/SortableJS/…

参考博客1:www.jb51.net/article/236…

参考博客2:blog.csdn.net/weixin_4388…

参考博客3:blog.csdn.net/DZYMY/artic…

2:需求如下

1680590543389.png

查询条件的代码如下:

1680591002062.png

字段设置的代码如下:

字段设置输入框不可拖动之后发现输入框没法聚焦了,又给输入框外层套了个div写了个myInpClick事件

1680591114010.jpg

引入sortablejs

1680591174593.png

js代码如下:

1680591395848.png

整个界面代码:

<template>
  <div class="query-form-panel">
    <ys-nav class="query-toolbar">
      <div class="query-name">
        <span> <b class="red">*</b>查询名称: </span>
        <el-input v-model="queryName" size="small" placeholder="查询名称" />
      </div>
      <div class="title-btns">
        <el-button type="primary" size="small" @click="handleSave()"
          >保存</el-button
        >
      </div>
    </ys-nav>

    <div class="query-form-body">
      <!-- 数据筛选 -->
      <div class="query-form">
        <div class="query-form-title">
          数据筛选
          <div class="title-btns">
            <el-button type="primary" @click="addFilter()">新增</el-button>
          </div>
        </div>
        <div class="query-from-body">
          <el-table
            :row-key="getRowKey"
            :data="filterData"
            style="width: 100%"
            empty-text="请新增数据"
            :span-method="arraySpanMethod"
            :cell-class-name="cellClass"
          >
            <el-table-column width="60" align="center">
              <template #default="scope">
                <i
                  class="filter-icon el-icon-plus"
                  @click="insertFilterItem(scope.row, scope.$index)"
                ></i>
                <i
                  class="filter-icon el-icon-close"
                  @click="deleteFilterItem(scope.row, scope.$index)"
                ></i>
              </template>
            </el-table-column>
            <el-table-column width="50" align="center">
              <template slot="header">
                <el-button type="text" @click="addGroup()">分组</el-button>
              </template>
              <template #default="scope">
                <el-checkbox v-model="scope.row.checked" />
              </template>
            </el-table-column>
            <el-table-column
              label="分组详情"
              v-if="filterGroupData.length"
              min-width="10"
              align="center"
              class="group-column"
            >
              <template #default style="vertical-align: top">
                <table
                  border="0"
                  cellpadding="0"
                  cellspacing="0"
                  class="group-table"
                >
                  <tr v-for="(item, index) in filterData" :key="index">
                    <td
                      v-for="level in showLevelLength(index)"
                      :key="level"
                      class="level"
                      :style="calcLevelStyle(index, level).style"
                    >
                      <i
                        v-if="calcLevelStyle(index, level).isFirst"
                        class="icon el-icon-close"
                        title="删除分组"
                        @click="deleteGroup(index, level)"
                      ></i>
                    </td>
                  </tr>
                </table>
              </template>
            </el-table-column>
            <el-table-column label="与/或" width="100">
              <template #default="scope">
                <el-select
                  v-if="scope.$index"
                  v-model="scope.row.logic"
                  placeholder="请选择"
                  size="mini"
                >
                  <el-option
                    v-for="item in filterWith"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  ></el-option>
                </el-select>
              </template>
            </el-table-column>
            <el-table-column prop="label" label="字段" width="200">
              <template #default="scope">
                <div
                  class="handleHref"
                  @click="editFilter(scope.row, scope.$index)"
                >
                  {{ scope.row.source + "*" + scope.row.label }}
                </div>
              </template>
            </el-table-column>
            <el-table-column prop label="运算符" width="200">
              <template #default="scope">
                <el-select
                  v-model="scope.row.operator"
                  placeholder="请选择"
                  size="mini"
                >
                  <el-option
                    v-for="item in filterOperation.filter(
                      (x) => !scope.row.op || (scope.row.op & x.flag) === x.flag
                    )"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  ></el-option>
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="值">
              <template #default="scope">
                <value-inputs
                  :field="scope.row"
                  :operator="scope.row.operator"
                />
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>

      <!-- 查询条件 -->
      <div class="query-form">
        <div class="query-form-title">
          查询条件
          <div class="title-btns">
            <el-button type="primary" @click="addSearch()">新增</el-button>
          </div>
        </div>
        <div class="query-from-body tagBox" style="padding: 14px 20px 20px 20px">
          <el-tag
            v-for="(item, index) in searchData"
            :key="item.criteriaIndex"
            closable
            size="lager"
            @close="handleClose(index)"
            >{{ item.label }}</el-tag
          >
        </div>
      </div>

      <!-- 字段设置 -->
      <div class="query-form">
        <div class="query-form-title">字段设置</div>
        <div class="query-from-body" style="padding: 20px">
          <!-- <el-checkbox
            v-model="isPaging"
            :disabled="!query || query.ownerId !== '0'"
            style="display: block; margin: 0px 0 12px 0"
            >是否分页</el-checkbox
          > -->
          <el-checkbox
            v-model="autoLoad"
            style="display: block; margin: 0px 0 12px 0"
            >是否自动加载</el-checkbox
          >
          <el-table
            :data="columnConfig"
            stripe
            style="width: 100%"
            row-key="field"
            class="drop-table"
          >
            <el-table-column
              type="index"
              width="55"
              align="center"
            ></el-table-column>

            <el-table-column
              prop="label"
              label="名称"
              width="200"
            ></el-table-column>
            <el-table-column width="100" align="center">
              <template #header>
                <el-checkbox v-model="columnCheckAll">是否显示</el-checkbox>
              </template>
              <template #default="scope">
                <el-checkbox
                  v-if="scope.row.displayable"
                  v-model="scope.row.visible"
                />
              </template>
            </el-table-column>
            <el-table-column label="列宽" width="150">
              <template #default="scope">
                <div @click="myInpClick(scope.$index)">
                    <el-input
                      v-if="scope.row.displayable && scope.row.visible"
                      v-model="scope.row.width"
                      @pointerDown.stop
                      clearable
                      :ref="'myInp'+scope.$index"
                  ></el-input>
                </div>

              </template>
            </el-table-column>
            <el-table-column label="冻结列" width="150">
              <template #default="scope">
                <el-select
                  v-if="scope.row.displayable && scope.row.visible"
                  v-model="scope.row.frozen"
                  placeholder="请选择"
                  size="mini"
                  clearable
                >
                  <el-option
                    v-for="item in frozenList"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  ></el-option>
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="排序" width="150">
              <template #default="scope">
                <el-select
                  v-if="scope.row.filterable"
                  v-model="scope.row.sort"
                  @change="onSortChange(scope.row)"
                  size="mini"
                  clearable
                >
                  <el-option :value="1" label="正排" />
                  <el-option :value="-1" label="倒排" />
                </el-select>
              </template>
            </el-table-column>
            <el-table-column label="排序优先级" width="150">
              <template #default="scope">
                <el-input-number
                  v-if="scope.row.filterable && scope.row.sort"
                  v-model="scope.row.sortPriority"
                ></el-input-number>
              </template>
            </el-table-column>
            <el-table-column label="分组" width="100" align="center">
              <template #default="scope">
                <el-checkbox
                  v-if="scope.row.filterable"
                  v-model="scope.row.groupBy"
                />
              </template>
            </el-table-column>
            <el-table-column prop="statis" label="统计">
              <template #default="scope">
                <el-select
                  v-if="
                    scope.row.filterable &&
                      scope.row.displayable &&
                      !scope.row.groupBy
                  "
                  v-model="scope.row.statis"
                  placeholder="请选择"
                  size="mini"
                  clearable
                >
                  <el-option
                    v-for="item in statisList"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  ></el-option>
                </el-select>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
    </div>

    <!-- 新增筛选对话框 -->
    <el-dialog
      :title="addType === 'filter' ? '新增筛选' : '新增查询'"
      :visible.sync="dialogVisible"
      width="1000px"
      :modal="false"
      :close-on-click-modal="false"
      class="meta-dialog"
    >
      <i class="dialog-close el-icon-close" @click="dialogVisible = false"></i>
      <el-tabs
        type="border-card"
        v-model="activeTabName"
        @tab-click="handleTabsClick"
      >
        <el-tab-pane
          v-for="(item, tabKey) in tabsData"
          :key="tabKey"
          :name="tabKey"
          :label="getLabel(tabKey)"
        >
          <el-checkbox-group
            v-model="checkList"
            v-if="addType === 'search' || addType === 'filterEdit'"
          >
            <div v-for="(tag, key, index) in item" :key="index">
              <div class="check-group-title">{{ key }}</div>
              <el-checkbox
                class="checkbox-item"
                v-for="moduleTag in tag"
                :key="`${moduleTag.source}.${moduleTag.field}`"
                :label="`${moduleTag.source}.${moduleTag.field}`"
                @change="(checked) => handleChange(checked, moduleTag, tabKey)"
                border
                >{{ moduleTag.label }}</el-checkbox
              >
            </div>
          </el-checkbox-group>
          <span v-else v-for="(tag, key, index) in item" :key="index">
            <div class="check-group-title">{{ key }}</div>
            <el-button
              v-for="(moduleTag, index) in tag"
              :key="index"
              :label="moduleTag.field"
              @click="addFilterItem(moduleTag, tabKey)"
              size="small"
              >{{ moduleTag.label }}</el-button
            >
          </span>
        </el-tab-pane>
      </el-tabs>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false" size="small">关 闭</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import Vue from "vue";
import Sortable from "sortablejs";

import { getMetaData, getQuery, submit, getViewDetail } from "./api";

import { getCustomerTagDef } from "@/services/customer";

import { getUserContext } from "@/utils/userContext.js";
import { groupData, getLevel } from "@/utils/data_formatter";

import ValueInputs from "./ValueInputs";

let groupColorConfig = ["#F9EBEB", "#FFF4CE", "#EFF6FC", "#DFF6DD"];

export default {
  components: {
    "value-inputs": ValueInputs,
  },

  props: ["queryId", "viewName"],

  data() {
    return {
      metaData: [],
      queryMeta: [],
      query: null,

      aliasMapping: {},
      tabsData: {},

      // 当前选中的 tab
      activeTabName: "",

      dialogVisible: false,
      filedDialogVisible: false,
      isPaging: true,
      autoLoad: true,
      queryName: "",
      addType: "",
      editRow: "",
      checkList: [],
      metaInitData: [],
      metaGroupData: [],
      columnConfig: [],
      columnCheckAll: false,
      levelLength: 0,
      filterGroupData: [],
      filterData: [],
      filterWith: [
        { value: "and", label: "与" },
        { value: "or", label: "或" },
      ],
      filterOperation: [
        { value: "=", label: "=", flag: 1 },
        { value: "<>", label: "<>", flag: 2 },
        { value: ">", label: ">", flag: 16 },
        { value: "<", label: "<", flag: 32 },
        { value: ">=", label: ">=", flag: 64 },
        { value: "<=", label: "<=", flag: 128 },
        { value: "like", label: "包含(like)", flag: 4 },
        { value: "not_like", label: "不包含(not like)", flag: 8 },
        { value: "in", label: "在组中(in)", flag: 256 },
        { value: "not_in", label: "不在组中(not in)", flag: 512 },
        { value: "is_null", label: "为空(null)", flag: 1024 },
        { value: "not_null", label: "不为空(not null)", flag: 2048 },
      ],
      searchData: [],

      frozenList: [
        { value: 0, label: "左侧" },
        { value: 1, label: "右侧" },
      ],
      statisList: [
        { value: "sum", label: "求和" },
        { value: "avg", label: "平均值" },
        { value: "count", label: "计数" },
        { value: "distinct_count", label: "去重计数" },
        { value: "min", label: "最小值" },
        { value: "max", label: "最大值" },
      ],
      draged: false,

      options: [],
    };
  },

  computed: {
    // showTabs() {
    //   return (tabData) => {
    //     var _data = { ...tabData };
    //     if (this.addType === "search" && _data["customerTag"]) {
    //       // delete _data["customerTag"];
    //       return _data;
    //     } else {
    //       return _data;
    //     }
    //   };
    // },
    getLabel() {
      return (key) => {
        return key == "customerQuery"
          ? "客户信息"
          : key == "customerTag"
          ? "客户标签"
          : key == "productQuery"
          ? "产品信息"
          : "查询视图字段";
      };
    },
    showLevelLength() {
      return (rowIndex) => {
        let allRows = [];
        rowIndex++;
        this.filterGroupData.map((val) => {
          for (let i = val.start; i <= val.end; i++) {
            allRows.includes(i) ? "" : allRows.push(i);
          }
        });
        if (allRows.includes(rowIndex)) {
          return this.levelLength;
        } else {
          return [];
        }
      };
    },
    isShowClose() {
      return (rowIndex, level) => {
        return false;
      };
    },
    calcLevelStyle() {
      return (rowIndex, level) => {
        rowIndex++;
        let levelData = this.filterGroupData.filter((val) => {
          return (
            val.level === level && rowIndex >= val.start && rowIndex <= val.end
          );
        });
        if (!levelData.length) {
          return false;
        }
        let levelList = [];
        levelData.map((val) => {
          for (let i = val.start; i <= val.end; i++) {
            levelList.push(i);
          }
        });
        let returnvalue = {
          style: {
            background: groupColorConfig[level % 4 > 1 ? (level % 4) - 1 : 0],
            borderLeft: "1px solid #C8C8C8",
          },
          isFirst: false,
        };

        if (rowIndex === levelList[0]) {
          returnvalue.style = {
            background: groupColorConfig[level % 4 > 1 ? (level % 4) - 1 : 0],
            borderTop: "1px solid #C8C8C8",
            borderLeft: "1px solid #C8C8C8",
          };
          returnvalue.isFirst = true;
        } else if (rowIndex === levelList[levelList.length - 1]) {
          returnvalue.style = {
            background: groupColorConfig[level % 4 > 1 ? (level % 4) - 1 : 0],
            borderBottom: "1px solid #C8C8C8",
            borderLeft: "1px solid #C8C8C8",
          };
        }
        return returnvalue;
      };
    },
  },

  watch: {
    columnCheckAll(v) {
      this.columnConfig.map((val) => {
        if (val.displayable) {
          val.visible = v;
        }
      });
    },
    checkList(v) {
      console.log("checkList", v);
    },
  },

  async mounted() {
    await this.initMeta();

    if (this.queryId > -1) {
      await this.initQuery();
    }

    await this.initColumnField();
  },

  methods: {
    getRowKey(row) {
      return row.field;
    },

    // 初始化元数据
    async initMeta() {
      const meta = await getMetaData(this.viewName);
      this.metaData = meta;
      this.queryMeta = meta.filter((x) => x.viewName === this.viewName)[0];

      for (let val of meta) {
        this.aliasMapping[val.viewName] = val.alias;

        this.tabsData[val.viewName] = groupData(
          val.queryFieldMetaDtoList
            .map((x) => ({ ...x, source: val.alias }))
            .filter((x) => x.filterable),
          "group"
        );

        // 设置 customerTag,点选页面时懒加载
        if (val.viewName === "customerQuery") {
          this.tabsData["customerTag"] = {};
          this.aliasMapping["customerTag"] = "tag";
        }
      }

      this.activeTabName = Object.keys(this.tabsData)[0];
    },

    // 初始化查询设置
    async initQuery() {
      const res = await getQuery(this.queryId);
      this.query = res;

      console.log("query", this.query);

      // for (let val of res.filters) {
      //   val.checked = false;
      // }

      this.filterData = res.filters.map((x) => {
        const fieldMeta = this.queryMeta.queryFieldMetaDtoList.filter((y) => {
          return x.source === "tag" ? y.tag === x.field : y.field === x.field;
        })[0];

        let value;

        switch (x.operator) {
          case "in":
          case "not in":
            value = JSON.parse(`[${x.value}]`);
            break;
          default:
            value = x.value;
            break;
        }

        const re = { ...fieldMeta, ...x, value };
        return re;
      });

      this.searchData = res.criterias;

      this.isPaging = res.isPage ? true : false;
      this.autoLoad = res.autoLoad ? true : false;
      this.queryName = res.queryName;
      this.filterGroupData = res.filterGroups || [];

      this.levelLength = 0;

      this.filterGroupData.map((val) => {
        this.levelLength = Math.max(this.levelLength, val.level);
      });
    },

    async initColumnField() {
      const map = this.query
        ? new Map(this.query.displayFields.map((x) => [x.field, x]))
        : new Map();

      const data = this.queryMeta.queryFieldMetaDtoList
        .filter((x) => x.displayable || x.filterable)
        .map((x) => {
          const {
            displayFieldId,
            visible,
            width,
            frozen,
            sort,
            sortPriority,
            groupBy,
            statis,
          } = map.get(x.field) || {};

          return {
            ...x,
            displayFieldId,
            visible,
            width,
            frozen,
            sort,
            sortPriority,
            groupBy,
            statis,
          };
        })
        .sort((a, b) => a.displayFieldId - b.displayFieldId);

      this.columnConfig = data;

      if (!this.draged) {
        this.drage = true;
        await this.$nextTick();
        this.rowDrop();
      }
    },

    // 自动设置排序顺序
    onSortChange(row) {
      if (!row.sort || row.sortPriority) return;

      const max = this.columnConfig
        .map((x) => x.sortPriority || 0)
        .reduce((a, b) => Math.max(a, b));

      row.sortPriority = max + 1;
    },

    //输入框验证
    verif(row) {
      //数字不通过
      if (isNaN(row.value) && row.validator === "number") {
        row.unValidator = true;
      } else {
        row.unValidator = false;
      }
    },

    async handleTabsClick() {
      // 加载客户标签
      if (
        this.activeTabName === "customerTag" &&
        !Object.values(this.tabsData.customerTag).length
      ) {
        let data = {};

        const tags = await getCustomerTagDef();

        for (let x of tags) {
          const category = `${x.category1} / ${x.category2}`;

          if (!data[category]) {
            data[category] = [];
          }

          let tag = { label: x.tag, field: x.tagId };

          if (x.enum) {
            tag.enumValues = x.enumValues;
          }

          data[category].push(tag);
        }

        this.$set(this.tabsData, "customerTag", data);
        this.$forceUpdate();
      }
    },

    // 添加分组
    addGroup() {
      let toGroupData = this.filterData.filter((val, index) => {
        val.$index = index;
        return val.checked === true;
      });
      //单个判断
      if (toGroupData.length <= 1) {
        $message.error("请选择至少两条数据分组!");
        return;
      }
      //连续判断
      for (var i = 1; i < toGroupData.length; i++) {
        if (toGroupData[i].$index - toGroupData[i - 1].$index !== 1) {
          $message.error("请选择连续的数据!");
          return false;
        }
      }
      //交叉判断
      var _pushData = {
        start: toGroupData[0].$index + 1,
        end: toGroupData[0].$index + toGroupData.length,
      };

      for (var i = 0; i < this.filterGroupData.length; i++) {
        let item = this.filterGroupData[i];
        if (
          _pushData.start < item.start &&
          _pushData.end < item.end &&
          _pushData.end >= item.start
        ) {
          $message.error("分组不允许交叉");
          return false;
        } else if (
          _pushData.end > item.end &&
          _pushData.start > item.start &&
          _pushData.start <= item.end
        ) {
          $message.error("分组不允许交叉");
          return false;
        } else if (_pushData.end == item.end && _pushData.start == item.start) {
          $message.error("分组不允许交叉");
          return false;
        }
      }
      var _filterGroupData = JSON.parse(JSON.stringify(this.filterGroupData));
      _filterGroupData.push(_pushData);
      this.filterGroupData = getLevel(_filterGroupData);
      this.levelLength = 0;
      this.filterGroupData.map((val) => {
        this.levelLength = Math.max(this.levelLength, val.level);
      });
      //清除所有选择
      this.filterData.map((val, index) => {
        val.checked = false;
      });
    },

    // 删除分组
    deleteGroup(rowIndex, level) {
      rowIndex++;
      this.filterGroupData = this.filterGroupData.filter((val) => {
        return !(val.level === level && val.start === rowIndex);
      });
      this.filterGroupData = getLevel(this.filterGroupData);
      this.levelLength = 0;
      this.filterGroupData.map((val) => {
        this.levelLength = Math.max(this.levelLength, val.level);
      });
    },

    cellClass({ row, column, rowIndex, columnIndex }) {
      return "";

      if (columnIndex === 2) {
        // 指定列号
        return "drawGroup";
      } else {
        return "";
      }
    },

    arraySpanMethod({ row, column, rowIndex, columnIndex }) {
      if (columnIndex == 2 && this.filterGroupData.length) {
        if (rowIndex == 0) {
          return {
            rowspan: this.filterData.length,
            colspan: 1,
          };
        } else {
          return {
            rowspan: 0,
            colspan: 0,
          };
        }
      }
    },

    async handleSave() {

      // console.log("数组顺序变了吗???===",this.searchData)
      // return

      if (!this.queryName) {
        $message.error("请输入查询名称!");
        return false;
      }

      // 数据筛选验证
      let errors = this.filterData.filter((x) => x.unValidator);

      if (errors.length) {
        $message.error(`数据筛选设置有误:${errors.map((x) => x.label)}`);
        return false;
      }

      // 分组数据验证
      const groupBy = this.columnConfig.filter((x) => x.groupBy).length;

      // if (groupBy) {
      //   errors = this.columnConfig.filter(
      //     (x) => !x.groupBy && x.visible && !x.statis
      //   );

      //   if (errors.length) {
      //     $message.error(
      //       `字段设置有误,未分组的字段如需显示,需要选择统计方式:${errors.map(
      //         (x) => x.label
      //       )}`
      //     );
      //     return false;
      //   }
      // }

      this.searchData.map((val, index) => {
        val.criteriaIndex = index + 1;
        val.criteriaFieldName = val.field;
      });

      this.filterData.map((val, index) => {
        val.filterIndex = index + 1;
        val.filterFieldName = val.field;
      });

      // this.columnConfig.map((val, index) => {
      //   val.displayFieldIndex = index + 1;
      //   val.displayFieldName = val.field;
      // });

      const filters = this.filterData.map((x) => {
        switch (x.operator) {
          case "in":
          case "not in":
            return { ...x, value: x.value.join() };
          default:
            return { ...x };
        }
      });

      let _data = {
        ownerId: this.query ? this.query.ownerId : getUserContext().userId,
        queryDefId: this.queryId == -1 ? null : this.queryId,
        isPage: this.isPaging ? 1 : 0,
        autoLoad: this.autoLoad ? 1 : 0,
        viewName: this.viewName,
        queryName: this.queryName,
        criterias: this.searchData,
        filters,
        displayFields: this.columnConfig,
        filterGroups: this.filterGroupData,
      };

      await submit(_data);
      $message.success("保存成功!");
      window.opener.location.reload();
      window.close();
    },

    addFilter() {
      this.addType = "filter";
      this.dialogVisible = true;
    },

    editFilter(row, index) {
      this.editRow = row;
      this.editIndex = index;
      this.addType = "filterEdit";
      this.checkList = [];
    },

    addSearch() {
      this.activeTabName = Object.keys(this.tabsData)[0];
      this.checkList = [];
      this.searchData.map((val) => {
        this.checkList.push(`${val.source}.${val.field}`);
      });
      this.addType = "search";
      this.dialogVisible = true;
      this.$forceUpdate();
    },

    handleClose(index) {
      this.searchData.splice(index, 1);
    },

    addFilterItem(row, tabKey) {
      row.source = this.aliasMapping[tabKey];
      if (this.addType === "filterInsert") {
        this.editIndex++;
        //重新统计分组
        this.reloadLevel(this.initSertIndex, "insert");
        let _row = { ...row };
        _row.checked = false;
        this.$set(_row, "logic", "and");
        if (_row.loadType == "dateRange") {
          this.$set(_row, "operator", "between");
        } else {
          this.$set(_row, "operator", "=");
        }
        this.$set(_row, "value", "");
        this.$set(_row, "unValidator", false);
        this.filterData.splice(this.editIndex, 0, _row);
        $message.success("插入一条数据");
      } else if (this.addType === "filter") {
        let _row = { ...row };
        this.$set(_row, "logic", "and");

        if (_row.loadType == "dateRange") {
          this.$set(_row, "operator", "between");
        } else {
          this.$set(_row, "operator", "=");
        }

        this.$set(_row, "value", "");
        this.$set(_row, "unValidator", false);
        _row.checked = false;
        this.filterData.push(_row);
        $message.success("添加一条数据");
      }

      // console.log("addFilterItem", row, this.filterData);
    },

    reloadLevel(rowIndex, type) {
      let _index = rowIndex + 1;
      let _filterGroupData = [];
      for (var i = 0; i < this.filterGroupData.length; i++) {
        var levelItem = this.filterGroupData[i];

        if (
          type == "delete" &&
          _index >= levelItem.start &&
          _index <= levelItem.end
        ) {
          levelItem.end--;
          if (levelItem.end !== levelItem.start) {
            _filterGroupData.push(levelItem);
          }
        }
        if (
          type == "insert" &&
          _index > levelItem.start &&
          _index <= levelItem.end
        ) {
          levelItem.end++;
          _filterGroupData.push(levelItem);
        } else {
          _filterGroupData.push(levelItem);
        }
      }
      this.filterGroupData = getLevel(_filterGroupData);
    },

    deleteFilterItem(row, rowIndex) {
      this.reloadLevel(rowIndex, "delete");

      this.filterData = this.filterData.filter((val, index) => {
        return rowIndex !== index;
      });
      $message.warning("删除一条数据");
    },

    insertFilterItem(row, rowIndex) {
      this.editIndex = rowIndex - 1;
      this.initSertIndex = rowIndex - 1;
      this.addType = "filterInsert";
      this.dialogVisible = true;
    },

    handleChange(checked, item, tabKey) {
      console.log("con: handleChange -> item", item);
      console.log("handleChange", item.source, item.field, tabKey);
      item.source = this.aliasMapping[tabKey];
      if (this.addType === "filterEdit") {
        this.filterData.map((val, index) => {
          if (index === this.editIndex) {
            Object.assign(val, item);
            $message.success("修改一条数据");
            this.dialogVisible = false;
          }
        });
      } else if (this.addType === "search") {
        let checkIndex = -1;
        for (var i = 0; i < this.searchData.length; i++) {
          if (
            `${this.searchData[i].source}.${this.searchData[i].field}` ===
            `${item.source}.${item.field}`
          ) {
            checkIndex = i;
            break;
          }
        }
        if (checked && checkIndex < 0) {
          $message.success("添加一条数据");
          this.searchData.push(item);
        } else if (!checked && checkIndex >= 0) {
          $message.warning("移除一条数据");
          this.searchData.splice(checkIndex, 1);
        }
      }
    },

    // 字段设置 拖拽
    rowDrop() {
      // 此时找到的元素是要拖拽元素的父容器
      const tbody = document.querySelector(
        ".drop-table .el-table__body-wrapper tbody"
      );
      const _this = this;
      Sortable.create(tbody, {
        //  指定父元素下可被拖拽的子元素
        draggable: ".el-table__row",
        filter:".el-input",
        onEnd({ newIndex, oldIndex }) {
          var _data = JSON.parse(JSON.stringify(_this.columnConfig));
          const currRow = _data.splice(oldIndex, 1)[0];
          _data.splice(newIndex, 0, currRow);
          _this.columnConfig = _data;
          console.log(_this.columnConfig)
        },
      });
      // 查询条件可拖拽
      const tagBody = document.querySelector(
        ".tagBox"
      );
      Sortable.create(tagBody, {
        draggable: ".el-tag",
        onEnd({ newIndex, oldIndex }) {
          var _tagData = JSON.parse(JSON.stringify(_this.searchData));         
          const tagIndex = _tagData.splice(oldIndex,1)[0];
          _tagData.splice(newIndex,0,tagIndex);
          _this.searchData = _tagData;
        },
      });

    },
    
    myInpClick(index){
      let ref = eval('this.$refs.myInp' + index)
      ref.focus()
    }

  },
};
</script>

<style lang="scss" scoped>
$padding-right: rpx(20);

.el-popover.danger {
  color: $danger !important;
  padding: rpx(12);
  background: $danger-bg;
  .popper__arrow {
    &:after {
      border-top-color: $danger-bg;
    }
  }
}

.el-tab-pane {
  .el-button {
    margin-top: rpx(12);
    margin-right: rpx(12);
    margin-left: 0 !important;
  }
}
.el-checkbox.is-bordered {
  margin-top: rpx(6);
  margin-left: 0 !important;
}
.group-column {
  vertical-align: top;
}

/deep/ .el-table--enable-row-hover .el-table__body tr:hover > td.drawGroup {
  vertical-align: top;
  background: transparent !important;
}
.group-table {
  margin: 0 auto;
  tr {
    height: 30px;
    &:hover {
      td {
        background: none;
      }
    }
  }
  td {
    border: 0;
  }
}
.level {
  width: rpx(20);
  height: rpx(30);
  background: #fff;
  text-align: center;
  .icon {
    cursor: pointer;
    font-size: rpx(16);
  }
}

.check-group-title {
  font-size: rpx(14);
  color: $subtext;
  padding: rpx(12) 0 rpx(6) 0;
}
.dialog-close {
  position: absolute;
  right: rpx(20);
  top: rpx(11);
  color: #409eff;
  z-index: 100;
  font-size: rpx(18);
  cursor: pointer;
}
.handleHref {
  cursor: pointer;
  color: #409eff;
  border-bottom: 1px solid $link-color;
  display: inline-block;
  line-height: 1.5;
  padding: 0 rpx(6);
}

.query-form-panel {
  /deep/ .meta-dialog {
    .el-tabs {
      display: flex;
      flex-flow: column nowrap;
      border-left: 0;
      border-right: 0;
    }

    .el-tabs__content {
      padding: 0;
      overflow: scroll;
    }

    .el-tab-pane {
      padding: 0 rpx(15);
    }

    .el-tabs--border-card {
      box-shadow: none;
    }
    .el-dialog__header {
      display: none;
    }
    .el-dialog__body {
      padding: 0;
      height: rpx(600);
      .el-tabs {
        height: 100%;
      }
    }
    .checkbox-item {
      min-width: rpx(100);
    }
  }
  /deep/ .column-dialog {
    .el-dialog__body {
      overflow: auto;

      padding: 0;
    }
  }
  .query-toolbar {
    height: rpx(50);
    justify-content: space-between;
    padding-right: $padding-right;
    padding: 0 $padding-right;
    .query-name {
      font-size: rpx(16);
      color: $text-color;

      .el-input {
        width: auto;
      }

      &.active {
        border: $border;
      }
    }
  }
  .query-form {
    flex: 1;
    display: flex;
    flex-direction: column;

    .query-form-title {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0 $padding-right;
      line-height: rpx(36);
      background: $bg-color;
    }
    .query-from-body {
      flex: 1;
      padding: 0 $padding-right;
      .filter-icon {
        font-size: rpx(16);
        cursor: pointer;
        &.el-icon-close {
          color: $danger;
        }
        &.el-icon-plus {
          margin-right: rpx(6);
          color: $success;
        }
      }

      .el-popover__reference.el-button {
        border: none;
        padding: 0;
      }
      .el-tag {
        position: relative;
        margin: $padding-y $padding-x 0 0;
        height: rpx(26);
        line-height: rpx(24);
      }
      /deep/ .danger .el-input__inner {
        border-color: $danger;
      }
      /deep/ .el-input--mini .el-input__inner {
        height: rpx(24);
        line-height: rpx(24);
      }
      /deep/ .el-input--mini .el-input__icon {
        line-height: rpx(24);
      }
      /deep/ .el-table--mini td,
      .el-table--mini th {
        padding: 2px 0;
      }
    }
  }
}
</style>