002201 1 year ago
parent
commit
fd332f2fd7

+ 25 - 25
src/api/login.js

@@ -1,4 +1,4 @@
-import request from '@/utils/request'
+import request from "@/utils/request";
 
 // 登录方法
 export function login(username, password, code, uuid) {
@@ -6,54 +6,54 @@ export function login(username, password, code, uuid) {
     username,
     password,
     code,
-    uuid
-  }
+    uuid,
+  };
   return request({
-    url: '/login',
+    url: "/login",
     headers: {
-      isToken: false
+      isToken: false,
     },
-    method: 'post',
-    data: data
-  })
+    method: "post",
+    data: data,
+  });
 }
 
 // 注册方法
 export function register(data) {
   return request({
-    url: '/register',
+    url: "/register",
     headers: {
-      isToken: false
+      isToken: false,
     },
-    method: 'post',
-    data: data
-  })
+    method: "post",
+    data: data,
+  });
 }
 
 // 获取用户详细信息
 export function getInfo() {
   return request({
-    url: '/getInfo',
-    method: 'get'
-  })
+    url: "/getInfo",
+    method: "get",
+  });
 }
 
 // 退出方法
 export function logout() {
   return request({
-    url: '/logout',
-    method: 'post'
-  })
+    url: "/logout",
+    method: "post",
+  });
 }
 
 // 获取验证码
 export function getCodeImg() {
   return request({
-    url: '/captchaImage',
+    url: "/captchaImage",
     headers: {
-      isToken: false
+      isToken: false,
     },
-    method: 'get',
-    timeout: 20000
-  })
-}
+    method: "get",
+    timeout: 20000,
+  });
+}

+ 8 - 9
src/assets/styles/element-ui.scss

@@ -69,7 +69,7 @@
 // dropdown
 .el-dropdown-menu {
   a {
-    display: block
+    display: block;
   }
 }
 
@@ -91,18 +91,17 @@
   display: none;
 }
 
-
-.el-autocomplete-suggestion .el-autocomplete-suggestion__wrap{
+.el-autocomplete-suggestion .el-autocomplete-suggestion__wrap {
   padding: 10px 0 0 0;
-}   
+}
 
- .el-super-table {
+.el-super-table {
   width: 100%;
-  margin: 20px 0 0 0;
 }
- .el-super-table .el-table__cell {
+.el-super-table .el-table__cell {
   height: 50px;
 }
- .el-super-table td.el-table__cell {
+
+.el-super-table td.el-table__cell {
   border-right: 0;
-}
+}

+ 10 - 0
src/assets/styles/font.scss

@@ -0,0 +1,10 @@
+.fe-1 {
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+@for $i from 3 through 10 {
+  .fs-#{$i} {
+    font-size: 4px * $i;
+  }
+}

+ 29 - 20
src/assets/styles/index.scss

@@ -1,16 +1,20 @@
-@import './variables.scss';
-@import './mixin.scss';
-@import './transition.scss';
-@import './element-ui.scss';
-@import './sidebar.scss';
-@import './btn.scss';
+@import "./variables.scss";
+@import "./mixin.scss";
+@import "./transition.scss";
+@import "./element-ui.scss";
+@import "./sidebar.scss";
+@import "./btn.scss";
+@import "./margin.scss";
+@import "./padding.scss";
+@import "./font.scss";
 
 body {
   height: 100%;
   -moz-osx-font-smoothing: grayscale;
   -webkit-font-smoothing: antialiased;
   text-rendering: optimizeLegibility;
-  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
+    Microsoft YaHei, Arial, sans-serif;
 }
 
 label {
@@ -64,7 +68,6 @@ div:focus {
 .fl {
   float: left;
 }
-
 .pr-5 {
   padding-right: 5px;
 }
@@ -104,7 +107,8 @@ aside {
   display: block;
   line-height: 32px;
   font-size: 16px;
-  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
+  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
+    Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
   color: #2c3e50;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
@@ -134,7 +138,7 @@ aside {
 }
 
 .text-center {
-  text-align: center
+  text-align: center;
 }
 
 .sub-navbar {
@@ -145,7 +149,13 @@ aside {
   text-align: right;
   padding-right: 20px;
   transition: 600ms ease position;
-  background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
+  background: linear-gradient(
+    90deg,
+    rgba(32, 182, 249, 1) 0%,
+    rgba(32, 182, 249, 1) 0%,
+    rgba(33, 120, 241, 1) 100%,
+    rgba(33, 120, 241, 1) 100%
+  );
 
   .subtitle {
     font-size: 20px;
@@ -190,22 +200,21 @@ aside {
   z-index: 1000 !important;
 }
 
-
 /**修改全局的滚动条*/
 /**滚动条的宽度*/
 ::-webkit-scrollbar {
-	width: 8px;
+  width: 8px;
 }
 ::-webkit-scrollbar-thumb {
-	background-color: #eaecf1;
-	border-radius: 3px;
+  background-color: #eaecf1;
+  border-radius: 3px;
 }
 /*表格*/
 .el-table__body-wrapper::-webkit-scrollbar {
-	width: 10px;
-	height: 10px;
+  width: 10px;
+  height: 10px;
 }
 .el-table__body-wrapper::-webkit-scrollbar-thumb {
-	background-color: #a1a3a9;
-	border-radius: 3px;
-}
+  background-color: #a1a3a9;
+  border-radius: 3px;
+}

+ 23 - 0
src/assets/styles/margin.scss

@@ -0,0 +1,23 @@
+@for $i from 0 through 10 {
+  .m-#{$i} {
+    margin: 4px * $i;
+  }
+  .mx-#{$i} {
+    margin: 0 4px * $i;
+  }
+  .my-#{$i} {
+    margin: 4px * $i 0;
+  }
+  .mt-#{$i} {
+    margin-top: 4px * $i;
+  }
+  .mr-#{$i} {
+    margin-right: 4px * $i;
+  }
+  .mb-#{$i} {
+    margin-bottom: 4px * $i;
+  }
+  .ml-#{$i} {
+    margin-left: 4px * $i;
+  }
+}

+ 23 - 0
src/assets/styles/padding.scss

@@ -0,0 +1,23 @@
+@for $i from 0 through 8 {
+  .p-#{$i} {
+    padding: 4px * $i;
+  }
+  .px-#{$i} {
+    padding: 0 4px * $i;
+  }
+  .py-#{$i} {
+    padding: 4px * $i 0;
+  }
+  .pt-#{$i} {
+    padding-top: 4px * $i;
+  }
+  .pr-#{$i} {
+    padding-right: 4px * $i;
+  }
+  .pb-#{$i} {
+    padding-bottom: 4px * $i;
+  }
+  .pl-#{$i} {
+    padding-left: 4px * $i;
+  }
+}

+ 119 - 0
src/components/super-table/freeze.vue

@@ -0,0 +1,119 @@
+<template>
+  <el-button size="mini" @click="drawer = true">
+    {{ number ? `冻结列 :${number}` : "冻结列" }}
+    <el-drawer
+      :modal="false"
+      :visible.sync="drawer"
+      size="20%"
+      title="冻结列"
+      append-to-body
+    >
+      <el-input
+        v-model="key"
+        size="mini"
+        placeholder="请输入列名称"
+        style="width: 100%; padding: 0 16px 16px"
+      >
+      </el-input>
+      <el-row :gutter="20" style="margin: 0">
+        <el-draggable
+          v-model="columns"
+          :group="{ item: 'key' }"
+          @end="$emit('freeze')"
+        >
+          <el-col
+            v-for="({ item }, index) in searchColumns"
+            :key="index"
+            :span="24"
+            style="
+              display: flex;
+              justify-content: space-between;
+              padding: 12px 16px;
+            "
+          >
+            <span
+              style="
+                font-size: 13px;
+                flex: 1;
+                cursor: move;
+                padding: 0 12px 0 0;
+                text-overflow: ellipsis;
+                overflow: hidden;
+                word-break: break-all;
+                white-space: nowrap;
+              "
+            >
+              <i
+                class="el-icon-mouse"
+                style="color: #72767b; margin: 0 6px 0 0"
+              ></i>
+              <i
+                class="el-icon-user"
+                style="color: #72767b; margin: 0 6px 0 0"
+              ></i>
+              {{ item.title }}
+            </span>
+            <div>
+              <el-switch
+                v-model="item.fixed"
+                size="mini"
+                @change="$emit('freeze')"
+              ></el-switch>
+            </div>
+          </el-col>
+        </el-draggable>
+      </el-row>
+    </el-drawer>
+  </el-button>
+</template>
+
+<script>
+export default {
+  name: "",
+  components: {
+    ElDraggable: () => import("@/components/draggable/index.vue"),
+  },
+  props: {
+    value: {
+      type: Array,
+      require: true,
+    },
+  },
+  data() {
+    return {
+      drawer: false,
+      key: "",
+    };
+  },
+  computed: {
+    columns: {
+      get() {
+        return this.$props.value;
+      },
+      set(value) {
+        this.$emit("input", value);
+      },
+    },
+    searchColumns: {
+      get() {
+        return this.columns.filter(
+          ({ item }) => item.title.indexOf(this.key) > -1
+        );
+      },
+      set(value) {},
+    },
+    number: {
+      get() {
+        return this.columns.filter(({ item }) => item.fixed).length;
+      },
+      set(value) {},
+    },
+  },
+  watch: {},
+  methods: {},
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<style scoped></style>

+ 119 - 0
src/components/super-table/hide.vue

@@ -0,0 +1,119 @@
+<template>
+  <el-button size="mini" @click="drawer = true">
+    {{ number ? `隐藏列 :${number}` : "隐藏列" }}
+    <el-drawer
+      :modal="false"
+      :visible.sync="drawer"
+      size="20%"
+      title="隐藏列"
+      append-to-body
+    >
+      <el-input
+        v-model="key"
+        size="mini"
+        placeholder="请输入列名称"
+        style="width: 100%; padding: 0 16px 16px"
+      >
+      </el-input>
+      <el-row :gutter="20" style="margin: 0">
+        <el-draggable
+          v-model="columns"
+          :group="{ item: 'key' }"
+          @end="$emit('hide')"
+        >
+          <el-col
+            v-for="({ item }, index) in searchColumns"
+            :key="index"
+            :span="24"
+            style="
+              display: flex;
+              justify-content: space-between;
+              padding: 12px 16px;
+            "
+          >
+            <span
+              style="
+                font-size: 13px;
+                flex: 1;
+                cursor: move;
+                padding: 0 12px 0 0;
+                text-overflow: ellipsis;
+                overflow: hidden;
+                word-break: break-all;
+                white-space: nowrap;
+              "
+            >
+              <i
+                class="el-icon-mouse"
+                style="color: #72767b; margin: 0 6px 0 0"
+              ></i>
+              <i
+                class="el-icon-user"
+                style="color: #72767b; margin: 0 6px 0 0"
+              ></i>
+              {{ item.title }}
+            </span>
+            <div>
+              <el-switch
+                v-model="item.hidden"
+                size="mini"
+                @change="$emit('hide')"
+              ></el-switch>
+            </div>
+          </el-col>
+        </el-draggable>
+      </el-row>
+    </el-drawer>
+  </el-button>
+</template>
+
+<script>
+export default {
+  name: "",
+  components: {
+    ElDraggable: () => import("@/components/draggable/index.vue"),
+  },
+  props: {
+    value: {
+      type: Array,
+      require: true,
+    },
+  },
+  data() {
+    return {
+      drawer: false,
+      key: "",
+    };
+  },
+  computed: {
+    columns: {
+      get() {
+        return this.$props.value;
+      },
+      set(value) {
+        this.$emit("input", value);
+      },
+    },
+    searchColumns: {
+      get() {
+        return this.columns.filter(
+          ({ item }) => item.title.indexOf(this.key) > -1
+        );
+      },
+      set(value) {},
+    },
+    number: {
+      get() {
+        return this.columns.filter(({ item }) => !item.hidden).length;
+      },
+      set(value) {},
+    },
+  },
+  watch: {},
+  methods: {},
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<style scoped></style>

+ 329 - 160
src/components/super-table/index.vue

@@ -2,26 +2,70 @@
 export default {
   name: "SuperTable",
   props: {
+    // 数据
     value: {
       type: [Array],
       require: true,
     },
+    // 字典
     dict: {
       type: [Object],
       require: true,
     },
+    // 分页
+    page: {
+      type: [Object],
+      require: true,
+    },
+    // 模板
     columns: {
       type: [Array],
       require: true,
     },
-    stroage: {
+    // 是否显示序号
+    index: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否显示单选
+    radio: {
       type: Boolean,
       default: false,
     },
-    hideOperationColumns: {
+    // 是否显示多选
+    checkbox: {
       type: Boolean,
       default: false,
     },
+    // 是否显示分页
+    pagination: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否显示操作图标
+    iconOperation: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否显示操作按钮
+    buttonOperation: {
+      type: Boolean,
+      default: true,
+    },
+    // 是否禁止选择
+    selectable: {
+      type: Function,
+      default: () => {},
+    },
+
+    // stroage: {
+    //   type: Boolean,
+    //   default: false,
+    // },
+    // hideOperationColumns: {
+    //   type: Boolean,
+    //   default: false,
+    // },
   },
   components: {
     ElDictTag: () => import("@/components/DictTag/index.vue"),
@@ -30,28 +74,37 @@ export default {
     ElComputedInput: () => import("@/components/computed-input/index.vue"),
     ElPopoverSelectV2: () => import("@/components/popover-select-v2/index.vue"),
     ElComputedInputV2: () => import("@/components/computed-input-v2/index.vue"),
+    ButtonHide: () => import("./hide.vue"),
+    ButtonFreeze: () => import("./freeze.vue"),
+    IconHide: () => import("./once/hide.vue"),
+    IconSort: () => import("./once/sort.vue"),
+    IconFilter: () => import("./once/filter.vue"),
+    IconFreeze: () => import("./once/freeze.vue"),
   },
   data() {
-    const { columns, stroage } = this.$props;
-    const stroageKey = (
-      this.$parent.$parent.$options.name + "_table"
-    ).toUpperCase();
-    const loaclColumns = JSON.parse(localStorage.getItem(stroageKey));
-    const innerColumns = stroage && !!loaclColumns ? loaclColumns : columns;
+    const { columns } = this.$props;
+    const innerColumns = columns;
     return {
-      drawer: false,
-      visible: false,
-      top: 0,
-      left: 0,
-      stroageKey: stroageKey,
       innerColumns: innerColumns,
-      currentData: {},
+      rowKey: "id",
+      // 选择
+      selectData: [],
+      selectState: false,
+      // 过滤
+      filterData: [],
+      filterState: false,
     };
   },
   computed: {
     innerValue: {
       get() {
-        return this.value;
+        if (this.filterState) {
+          return this.filterData;
+        } else if (this.selectState) {
+          return this.selectData;
+        } else {
+          return this.$props.value;
+        }
       },
       set(value) {
         this.$emit("input", value);
@@ -59,77 +112,128 @@ export default {
     },
     showColumns: {
       get() {
-        const { stroage, hideOperationColumns } = this.$props;
-        return stroage && hideOperationColumns
-          ? this.innerColumns.filter(({ item }) => item.hidden)
-          : this.innerColumns;
+        return this.innerColumns.filter(({ item }) => item.hidden);
+      },
+      set() {},
+    },
+    filterRules: {
+      get() {
+        return Object.fromEntries(
+          this.innerColumns
+            .filter(({ item }) => item.filter && !!item.filter.length)
+            .map(({ item }) => [item.key, item.filter])
+        );
       },
+      set() {},
     },
   },
   watch: {
-    visible(value) {
-      if (value) {
-        document.body.addEventListener("click", this.hideContextmenu);
-        document.body.addEventListener("keydown", this.hideContextmenu);
-      } else {
-        document.body.removeEventListener("click", this.hideContextmenu);
-        document.body.removeEventListener("keydown", this.hideContextmenu);
-      }
+    filterRules: {
+      handler: function (newValue) {
+        function multiFilter(array, filters) {
+          const filterKeys = Object.keys(filters);
+          // filters all elements passing the criteria
+          return array.filter((item) => {
+            // dynamically validate all filter criteria
+            return filterKeys.every((key) => {
+              //ignore when the filter is empty Anne
+              if (!filters[key].length) return true;
+              return !!~filters[key].indexOf(item[key]);
+            });
+          });
+        }
+        this.filterState = JSON.stringify(newValue) !== "{}";
+        this.filterData = multiFilter(this.$props.value, newValue);
+      },
     },
   },
   methods: {
-    setColumns() {
-      const { stroageKey, innerColumns } = this;
+    //
+    onSelectionChange(value) {
+      this.selectData = value;
+    },
+    //
+    onCellStyle({ row, column }) {
+      const { selectable } = this.$props;
+      // 禁止状态
+      if (!selectable(row)) {
+        return {
+          cursor: "no-drop",
+        };
+      }
+      // 选中状态
+      // if (
+      //   column.label === "#" &&
+      //   this.selectData.find((item) => item.id === row.id)
+      // ) {
+      //   return {
+      //     color: "#fff",
+      //     backgroundColor: "#409EFF",
+      //   };
+      // }
+    },
+    //
+    onRowClick(row, column, event) {
+      const { radio, checkbox, selectable } = this.$props;
+      // 单选
+      if (radio && selectable(row)) {
+        this.selectData = [row];
+        this.innerValue = this.innerValue.map((item) => ({
+          ...item,
+          isChecked: item.id === row.id ? true : false,
+        }));
+        this.$emit("row-select", this.selectData);
+      }
+      // 多选
+      if (checkbox && selectable(row)) {
+        this.$refs.superTable.toggleRowSelection(
+          this.innerValue.find((item) => item.id === row.id)
+        );
+        this.$emit("row-select", this.selectData);
+      }
+    },
+    // 冻结
+    onHide() {
       this.$nextTick(() => {
         this.$refs.superTable.doLayout();
-        localStorage.setItem(stroageKey, JSON.stringify(innerColumns));
       });
     },
-    resetColumns() {
-      const { stroageKey, innerColumns } = this;
-      this.innerColumns = innerColumns.map(({ item, attr }) => ({
-        attr,
-        item: { ...item, hidden: true, fixed: false },
-      }));
+    // 排序
+    onSort(prop) {
+      const { key, sort } = prop;
       this.$nextTick(() => {
+        this.$refs.superTable.sort(key, sort);
         this.$refs.superTable.doLayout();
-        localStorage.removeItem(stroageKey);
       });
     },
-    openContextmenu(row, column, event) {
-      this.visible = true;
-      this.currentData = { row, column };
+    // 冻结
+    onFreeze() {
       this.$nextTick(() => {
-        // 鼠标坐标
-        const { x, y } = event;
-        // 侧边栏宽度
-        const [{ clientWidth: sideWidth }] =
-          document.getElementsByClassName("sidebar-container");
-        // 导航栏宽度
-        const { clientHeight: navHeight } =
-          document.getElementsByClassName("main-container")[0].firstChild;
-        // 菜单宽度
-        const [{ clientWidth: contextmenuWidth }] =
-          document.getElementsByClassName("el-super-table_contextmenu");
-        // 最大Y轴偏差
-        const maxLeft = this.$el.offsetWidth - contextmenuWidth;
-        if (x > maxLeft) {
-          this.left = maxLeft + 10;
-        } else {
-          this.left = x - sideWidth;
-        }
-        this.top = y - navHeight;
+        this.$refs.superTable.doLayout();
       });
     },
-    hideContextmenu(event) {
-      const { type } = event;
-      if (type === "click") {
-        this.visible = false;
-      }
-      if (type === "keydown") {
-        const { keyCode } = event;
-        if (keyCode === 27) this.visible = false;
-      }
+    // 过滤
+    onFilter() {
+      this.$nextTick(() => {
+        this.$refs.superTable.doLayout();
+      });
+    },
+    onFilters(value) {
+      const {
+        item: { key },
+        attr: { dictName },
+      } = value;
+      let dataList = [];
+      const dict = this.dict.type[dictName];
+      dataList = Array.from(
+        new Set(this.innerValue.map((item) => item[key]).filter((item) => item))
+      ).map((item) => ({
+        text: dictName
+          ? (dict.find((dictItem) => dictItem.value == item) || {}).label
+          : item,
+        value: item,
+      }));
+      return dataList;
     },
   },
   created() {},
@@ -139,25 +243,106 @@ export default {
 </script>
 
 <template>
-  <div class="el-super-table" @contextmenu.prevent.stop>
+  <div class="el-super-table">
     <el-table
       v-bind="$attrs"
       v-on="$listeners"
-      :data="innerValue"
-      border
       ref="superTable"
-      @row-contextmenu="openContextmenu"
+      border
+      :data="innerValue"
+      :row-key="rowKey"
+      :row-style="{ height: '50px' }"
+      :cell-style="onCellStyle"
+      :header-row-style="{ height: '50px' }"
+      @row-click="onRowClick"
+      @selection-change="onSelectionChange"
     >
-      <slot></slot>
+      <!-- 序号 -->
+      <el-table-column
+        v-if="index"
+        :resizable="false"
+        fixed
+        width="50"
+        label="序号"
+        align="center"
+        class="is-index"
+      >
+        <template slot-scope="scope">
+          {{ scope.$index + 1 }}
+        </template>
+      </el-table-column>
+      <!-- 多选 -->
+      <el-table-column
+        v-if="checkbox"
+        :column-key="rowKey"
+        :selectable="selectable"
+        fixed
+        width="50"
+        align="center"
+        type="selection"
+        reserve-selection
+      >
+      </el-table-column>
       <el-table-column
         v-for="({ item, attr }, index) in showColumns"
         :key="index"
         :prop="item.key"
         :label="item.title"
         :fixed="item.fixed"
-        :width="item.width || 250"
+        :width="item.width"
         show-overflow-tooltip
       >
+        <template slot="header" slot-scope="scope">
+          <template v-if="iconOperation">
+            <span
+              :style="{
+                color:
+                  item.sort ||
+                  item.fixed ||
+                  (item.filter && !!item.filter.length)
+                    ? '#1890ff'
+                    : '',
+              }"
+            >
+              {{ item.title }}
+            </span>
+            <icon-sort
+              v-model="item.sort"
+              class="icon-sort"
+              @sort="onSort(item)"
+              :style="{
+                color: item.sort ? '#1890ff' : '',
+                display: item.sort ? 'inline-block' : '',
+              }"
+            ></icon-sort>
+            <icon-freeze
+              v-model="item.fixed"
+              class="icon-freeze"
+              @freeze="onFreeze"
+              :style="{
+                color: item.fixed ? '#1890ff' : '',
+                display: item.fixed ? 'inline-block' : '',
+              }"
+            ></icon-freeze>
+            <icon-filter
+              v-model="item.filter"
+              class="icon-filter"
+              :filters="onFilters({ item, attr })"
+              @filter="onFilter"
+              :style="{
+                color: item.filter && item.filter.length ? '#1890ff' : '',
+                display:
+                  item.filter && item.filter.length ? 'inline-block' : '',
+              }"
+            ></icon-filter>
+            <icon-hide
+              v-model="item.hidden"
+              class="icon-hide"
+              @hide="onHide"
+            ></icon-hide>
+          </template>
+          <template v-else>{{ item.title }}</template>
+        </template>
         <template slot-scope="scope">
           <slot :name="item.key" v-bind="scope" :item="item" :attr="attr">
             <template v-if="attr.is">
@@ -212,98 +397,82 @@ export default {
         </template>
       </el-table-column>
     </el-table>
-    <el-drawer :visible.sync="drawer" size="25%" title="操作列" append-to-body>
-      <el-row :gutter="20" style="margin: 0">
-        <el-draggable
-          v-model="innerColumns"
-          :group="{ item: 'key' }"
-          @change="setColumns"
-        >
-          <el-col
-            v-for="({ item }, index) in innerColumns"
-            :key="index"
-            :span="24"
-            style="
-              display: flex;
-              justify-content: space-between;
-              padding: 15px 20px;
-            "
+    <div
+      v-if="pagination && buttonOperation"
+      style="
+        height: 57px;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+      "
+    >
+      <div>
+        <template v-show="selectState">
+          <el-button
+            v-show="selectState"
+            size="mini"
+            @click="selectState = !selectState"
           >
-            <span style="cursor: move">
-              <i class="el-icon-rank"></i>
-              {{ item.title }}
-            </span>
-            <div>
-              <el-radio-group
-                v-model="item.hidden"
-                :size="$attrs.size"
-                style="margin: 0 15px 0 0"
-                @change="setColumns"
-              >
-                <el-radio-button :label="true">显</el-radio-button>
-                <el-radio-button :label="false">隐</el-radio-button>
-              </el-radio-group>
-              <el-radio-group
-                v-model="item.fixed"
-                :size="$attrs.size"
-                @change="setColumns"
-              >
-                <el-radio-button :label="false">不</el-radio-button>
-                <el-radio-button label="left">左</el-radio-button>
-                <el-radio-button label="right">右</el-radio-button>
-              </el-radio-group>
-            </div>
-          </el-col>
-        </el-draggable>
-      </el-row>
-    </el-drawer>
-    <transition name="el-fade-in-linear">
-      <ul
-        v-show="visible"
-        :style="{ left: left + 'px', top: top + 'px' }"
-        class="el-super-table_contextmenu"
-      >
-        <li v-if="hideOperationColumns" @click="drawer = true">
-          <i class="el-icon-setting"></i>
-          <span>设置布局</span>
-        </li>
-        <li v-if="hideOperationColumns" @click="resetColumns">
-          <i class="el-icon-refresh"></i>
-          <span>重置布局</span>
-        </li>
-        <slot name="contextmenu" v-bind="currentData"> </slot>
-      </ul>
-    </transition>
+            所有列
+          </el-button>
+        </template>
+        <template v-show="!selectState">
+          <button-hide v-model="innerColumns" @hide="onHide"></button-hide>
+          <button-freeze
+            v-model="showColumns"
+            @freeze="onFreeze"
+          ></button-freeze>
+          <el-button
+            :disabled="!selectData.length"
+            size="mini"
+            @click="selectState = !selectState"
+          >
+            选择列
+            {{ selectData.length ? ` :${selectData.length}` : "" }}
+          </el-button>
+        </template>
+      </div>
+      <pagination
+        v-show="!selectState"
+        :total="page.total"
+        :page.sync="page.pageNum"
+        :limit.sync="page.pageSize"
+        @pagination="$emit('pagination', { ...$event })"
+        style="height: 32px; padding: 0 !important"
+      />
+    </div>
   </div>
 </template>
 
 <style lang="scss">
-.el-super-table .el-table {
-  overflow: hidden;
-  border-radius: 5px;
+.el-super-table {
+  position: relative;
 }
-.el-super-table_contextmenu {
-  margin: 0;
-  background: #fff;
-  z-index: 3000;
-  position: absolute;
-  list-style-type: none;
-  padding: 5px 0;
-  border-radius: 4px;
-  font-size: 12px;
-  font-weight: 400;
-  color: #333;
-  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-  li {
-    margin: 0;
-    padding: 7px 16px;
-    cursor: pointer;
-    &:hover {
-      background: #ddd;
-    }
-    span {
-      margin: 0 0 0 5px;
-    }
+.el-super-table .el-table__header .cell {
+  display: flex;
+  .icon-sort {
+    display: none;
+  }
+  &:hover .icon-sort {
+    display: inline-block;
+  }
+  .icon-freeze {
+    display: none;
+  }
+  &:hover .icon-freeze {
+    display: inline-block;
+  }
+  .icon-filter {
+    display: none;
+  }
+  &:hover .icon-filter {
+    display: inline-block;
+  }
+  .icon-hide {
+    display: none;
+  }
+  &:hover .icon-hide {
+    display: inline-block;
   }
 }
 </style>

+ 151 - 0
src/components/super-table/once/filter.vue

@@ -0,0 +1,151 @@
+<template>
+  <el-popover
+    v-if="filterData.length"
+    :visible-arrow="false"
+    width="auto"
+    trigger="hover"
+    placement="bottom"
+    popper-class="p-0"
+  >
+    <template>
+      <el-checkbox-group
+        v-model="selectData"
+        class="pt-3 px-3"
+        @change="onCheck"
+      >
+        <el-checkbox
+          v-for="item in filterData"
+          :key="item.value"
+          :label="item.value"
+          class="mr-0 mb-3"
+          style="display: block"
+        >
+          {{ item.text }}
+        </el-checkbox>
+      </el-checkbox-group>
+      <el-divider class="m-0"></el-divider>
+      <div
+        class="p-3"
+        style="min-width: 175px; display: flex; justify-content: space-between"
+      >
+        <el-checkbox
+          v-model="checkAll"
+          :indeterminate="indeterminate"
+          @change="onCheckAll"
+        >
+          全选
+        </el-checkbox>
+        <div>
+          <el-button type="text" class="p-0" @click="onReset">重置</el-button>
+          <el-button type="text" class="p-0" @click="onFilter">筛选</el-button>
+        </div>
+      </div>
+    </template>
+    <!-- <el-tooltip
+      slot="reference"
+      :disabled="disabled"
+      effect="dark"
+      content="筛选"
+      placement="top"
+    > -->
+    <i
+      slot="reference"
+      class="el-icon-search pl-1"
+      style="cursor: pointer; font-weight: 600; transition: 500ms"
+      :style="{ color: color }"
+      @click="onOpen"
+    ></i>
+    <!-- </el-tooltip> -->
+  </el-popover>
+</template>
+
+<script>
+export default {
+  name: "IconFilter",
+  components: {},
+  data() {
+    return {
+      disabled: false,
+      selectData: [],
+    };
+  },
+  props: {
+    value: {
+      type: Array,
+      require: true,
+    },
+    filters: {
+      type: Array,
+      require: true,
+    },
+  },
+  computed: {
+    innerValue: {
+      get() {
+        return this.$props.value;
+      },
+      set(value) {
+        this.$emit("input", value);
+      },
+    },
+    filterData: {
+      get() {
+        return this.$props.filters;
+      },
+      set() {},
+    },
+    indeterminate: {
+      get() {
+        const count = this.filterData.length;
+        const selectCount = this.selectData.length;
+        return selectCount > 0 && selectCount < count;
+      },
+      set() {},
+    },
+    checkAll: {
+      get() {
+        const count = this.filterData.length;
+        const selectCount = this.selectData.length;
+        return count === selectCount;
+      },
+      set() {},
+    },
+    color: {
+      get() {
+        return this.$props.value && this.$props.value.length ? "#1890ff" : "";
+      },
+      set() {},
+    },
+  },
+  watch: {},
+  methods: {
+    // 打开
+    onOpen() {
+      this.disabled = !this.disabled;
+    },
+    // 选中
+    onCheck() {
+      // const count = this.filterData.length;
+      // const selectCount = this.selectData.length;
+      // this.checkAll = count === selectCount;
+    },
+    // 全选
+    onCheckAll(value) {
+      this.selectData = value ? this.filterData.map((item) => item.value) : [];
+    },
+    // 重置
+    onReset() {
+      this.selectData = [];
+      this.innerValue = this.selectData;
+    },
+    // 筛选
+    onFilter() {
+      this.innerValue = this.selectData;
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<style scoped></style>

+ 53 - 0
src/components/super-table/once/freeze.vue

@@ -0,0 +1,53 @@
+<template>
+  <!-- <el-tooltip effect="dark" content="冻结" placement="top"> -->
+  <i
+    v-if="innerValue"
+    class="el-icon-lock pl-1"
+    style="color: #1890ff; cursor: pointer; font-weight: 600; transition: 500ms"
+    @click="onFreeze"
+  ></i>
+  <i
+    v-else
+    class="el-icon-unlock pl-1"
+    style="cursor: pointer; font-weight: 600; transition: 500ms"
+    @click="onFreeze"
+  ></i>
+  <!-- </el-tooltip> -->
+</template>
+
+<script>
+export default {
+  name: "IconFreeze",
+  components: {},
+  data() {
+    return {};
+  },
+  props: {
+    value: {
+      type: Boolean,
+      require: true,
+    },
+  },
+  computed: {
+    innerValue: {
+      get() {
+        return this.$props.value;
+      },
+      set(value) {
+        this.$emit("input", value);
+      },
+    },
+  },
+  watch: {},
+  methods: {
+    onFreeze() {
+      this.innerValue = !this.innerValue;
+      this.$emit("freeze");
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<style scoped></style>

+ 45 - 0
src/components/super-table/once/hide.vue

@@ -0,0 +1,45 @@
+<template>
+  <i
+    v-if="innerValue"
+    class="el-icon-circle-close pl-1"
+    style="cursor: pointer; font-weight: 600; transition: 500ms"
+    @click="onHide"
+  ></i>
+</template>
+
+<script>
+export default {
+  name: "IconHide",
+  components: {},
+  props: {
+    value: {
+      type: Boolean,
+      require: true,
+    },
+  },
+  data() {
+    return {};
+  },
+  computed: {
+    innerValue: {
+      get() {
+        return this.$props.value;
+      },
+      set(value) {
+        this.$emit("input", value);
+      },
+    },
+  },
+  watch: {},
+  methods: {
+    onHide() {
+      this.innerValue = !this.innerValue;
+      this.$emit("hide");
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<style scoped></style>

+ 53 - 0
src/components/super-table/once/sort.vue

@@ -0,0 +1,53 @@
+<template>
+  <!-- <el-tooltip effect="dark" content="排序" placement="top"> -->
+  <i
+    v-if="innerValue === 'descending'"
+    class="el-icon-bottom pl-1"
+    style="color: #1890ff; cursor: pointer; font-weight: 600; transition: 500ms"
+    @click="onSort(null)"
+  ></i>
+  <i
+    v-else
+    class="el-icon-top pl-1"
+    style="cursor: pointer; font-weight: 600; transition: 500ms"
+    @click="onSort('descending')"
+  ></i>
+  <!-- </el-tooltip> -->
+</template>
+
+<script>
+export default {
+  name: "IconSort",
+  components: {},
+  data() {
+    return {};
+  },
+  props: {
+    value: {
+      type: String,
+      require: true,
+    },
+  },
+  computed: {
+    innerValue: {
+      get() {
+        return this.$props.value;
+      },
+      set(value) {
+        this.$emit("input", value);
+      },
+    },
+  },
+  watch: {},
+  methods: {
+    onSort(value) {
+      this.innerValue = value;
+      this.$emit("sort");
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<style scoped></style>

+ 1 - 1
src/views/purchase/task/columns.js

@@ -75,7 +75,7 @@ export default function useColumns() {
     { item: { key: "unitName", title: "单位" }, attr: {} },
   ].map(({ item, attr }) => ({
     attr,
-    item: { ...item, hidden: true, fixed: false },
+    item: { ...item, hidden: true, width: 200 },
   }));
 
   const SearchColumns = [

+ 14 - 27
src/views/purchase/task/index.vue

@@ -57,6 +57,7 @@ export default {
             $index: (pageNum - 1) * pageSize + index + 1,
           }));
           this.page.total = total;
+          console.log("selectData", this.selectData);
         }
       } catch (err) {
         // catch
@@ -98,7 +99,8 @@ export default {
       this.useQuery(this.params, this.page);
     },
     // 选 择
-    useSelect(prop) {
+    useSelect(prop, value) {
+      console.log(prop, value);
       this.selectData = prop;
     },
     // 明 细
@@ -125,7 +127,7 @@ export default {
       @reset="useReset"
       @submit="useQuery(params, page)"
     ></el-super-search>
-    <div style="margin: 0 0 20px 0; text-align: right">
+    <div style="margin: 0 0 16px 0; text-align: right">
       <el-button-group>
         <thxq-button
           :size="size"
@@ -168,39 +170,24 @@ export default {
       :size="size"
       :dict="dict"
       :columns="TableColumns"
-      stroage
-      hideOperationColumns
-      @row-dblclick="useSee"
-      @selection-change="useSelect"
+      :selectable="setSelectable"
+      checkbox
+      @row-select="useSelect"
+      :page="page"
+      @pagination="useQuery(params, page)"
     >
-      <el-table-column fixed width="55" align="center" label="#" prop="$index">
-      </el-table-column>
-      <el-table-column
-        fixed
-        width="55"
-        align="center"
-        type="selection"
-        :selectable="setSelectable"
-      >
-      </el-table-column>
     </el-super-table>
-    <pagination
-      :total="page.total"
-      :page.sync="page.pageNum"
-      :limit.sync="page.pageSize"
-      @pagination="useQuery(params, page)"
-      style="height: 32px; margin: 20px 0 0 0; padding: 0 !important"
-    />
   </el-card>
 </template>
 <style scoped lang="scss">
 .el-card {
-  width: calc(100% - 20px);
+  width: calc(100% - 32px);
   height: 100%;
-  margin: 10px;
-  padding: 20px;
+  margin: 16px;
+  padding: 16px;
+  border-radius: 8px;
 }
 .el-button-group + .el-button-group {
-  margin: 0 0 0 10px;
+  margin: 0 0 0 8px;
 }
 </style>