ソースを参照

feat: device filter

Casper Dai 1 年間 前
コミット
86be5f5606

+ 176 - 0
src/components/form/TreeSelect/index.vue

@@ -0,0 +1,176 @@
+<template>
+  <el-select
+    ref="select"
+    v-bind="$attrs"
+    v-model="value"
+    :loading="loading"
+    :placeholder="placeholderProxy"
+    :clearable="clearableProxy"
+    popper-class="o-select-option"
+    @visible-change="onVisibleChange"
+    @change="onChange"
+  >
+    <!-- <el-option
+      v-for="option in options"
+      :key="option.value"
+      :label="option.label"
+      :value="option.value"
+    /> -->
+    <el-option
+      value=""
+      label=""
+    >
+      <el-tree
+        ref="selectTree"
+        :data="options"
+        :props="props"
+        @node-click="handleNodeClick"
+      />
+    </el-option>
+  </el-select>
+</template>
+
+<script>
+
+export default {
+  name: 'TreeSelect',
+  props: {
+    schema: {
+      type: Object,
+      required: true
+    },
+    placeholder: {
+      type: String,
+      default: void 0
+    },
+    clearable: {
+      type: [Boolean, String],
+      default: false
+    }
+  },
+  data () {
+    return {
+      loaded: false,
+      loading: false,
+      optionData: null,
+      props: {
+        label: this.schema.label || '',
+        value: this.schema.value || ''
+      },
+      value: ''
+    }
+  },
+  computed: {
+    placeholderProxy () {
+      return this.schema.placeholder || this.placeholder
+    },
+    clearableProxy () {
+      return !!this.schema.placeholder
+    },
+    options () {
+      if (this.loaded) {
+        return this.optionData || []
+      }
+      const { option } = this.schema
+      return this.$attrs.value && option ? [option] : []
+    }
+  },
+  created () {
+    const { options, remote } = this.schema
+    this.optionData = options
+    this.loaded = !remote
+  },
+  methods: {
+    onVisibleChange (visible) {
+      if (visible && !this.loaded && !this.loading) {
+        this.loading = true
+        this.loadSelectOptions(this.schema).then(
+          ({ data }) => {
+            this.optionData = data
+            this.loading = false
+            this.loaded = true
+          },
+          () => {
+            this.loading = false
+          }
+        )
+      }
+    },
+    handleNodeClick (node) {
+      this.$refs.select.blur() // 隐藏下拉框
+      console.log(node)
+      this.value = node[this.schema.label]
+      this.$emit('input', node[this.schema.value])
+      this.$emit('change', node[this.schema.value])
+    },
+    mergeCondition (condition) {
+      const { options, remote } = this.schema
+      if (remote) {
+        this.schema.condition = { ...this.schema, ...condition }
+        this.optionData = options
+        this.loaded = false
+      }
+    },
+    loadSelectOptions () {
+      const { pagination, remote, condition } = this.schema
+      return pagination
+        ? remote({
+          ...condition,
+          pageSize: 10,
+          pageNum: 1
+        }).then(({ data, totalCount }) => {
+          if (totalCount <= 10) {
+            return { data }
+          }
+          return remote({
+            ...condition,
+            pageSize: totalCount,
+            pageNum: 1
+          })
+        })
+        : remote(this.schema)
+    },
+    onChange (value) {
+      this.$emit('input', value)
+      this.$emit('change', value)
+    },
+    getOptions () {
+      return this.optionData || []
+    }
+  }
+}
+</script>
+<style scoped>
+.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
+  height: auto;
+  max-height: 274px;
+  padding: 0;
+  overflow: hidden;
+  overflow-y: auto;
+}
+.el-select-dropdown__item.selected {
+  font-weight: normal;
+}
+ul li >>> .el-tree .el-tree-node__content {
+  height: auto;
+  padding: 0 20px;
+}
+.el-tree-node__label {
+  font-weight: normal;
+}
+.el-tree >>> .is-current .el-tree-node__label {
+  color: #409eff;
+  font-weight: 700;
+}
+.el-tree >>> .is-current .el-tree-node__children .el-tree-node__label {
+  color: #606266;
+  font-weight: normal;
+}
+
+.el-theme1 .el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after{
+  content: '';
+}
+.serarchInput{
+  padding: 10px 20px;
+}
+</style>

+ 21 - 9
src/components/table/GridTable/index.vue

@@ -37,16 +37,28 @@
           :key="filter.key"
           class="l-flex--row"
         >
-          <schema-select
-            v-if="filter.type === 'select'"
-            v-model="options.params[filter.key]"
-            class="u-width--xs"
-            size="small"
-            :schema="filter"
-            @change="onChange"
-          />
+          <template v-if="filter.type === 'select'">
+            <schema-select
+              v-model="options.params[filter.key]"
+              :class="filter.className || 'u-width--xs'"
+              size="small"
+              :schema="filter"
+              @change="onChange"
+            />
+          </template>
+          <template v-if="filter.type === 'tree-select'">
+            <tree-select
+              v-model="options.params[filter.key]"
+              :class="filter.className || 'u-width--xs'"
+              :schema="filter"
+              size="small"
+              @change="onChange"
+            />
+          </template>
           <template v-if="filter.type === 'switch'">
-            <span class="c-sibling-item">{{ filter.placeholder }}</span>
+            <span class="c-sibling-item">
+              {{ filter.placeholder }}
+            </span>
             <el-switch
               v-model="options.params[filter.key]"
               class="c-sibling-item"

+ 18 - 8
src/components/table/Table/index.vue

@@ -38,14 +38,24 @@
           :key="filter.key"
           class="l-flex--row"
         >
-          <schema-select
-            v-if="filter.type === 'select'"
-            v-model="options.params[filter.key]"
-            :class="filter.className || 'u-width--xs'"
-            :schema="filter"
-            size="small"
-            @change="onChange"
-          />
+          <template v-if="filter.type === 'select'">
+            <schema-select
+              v-model="options.params[filter.key]"
+              :class="filter.className || 'u-width--xs'"
+              :schema="filter"
+              size="small"
+              @change="onChange"
+            />
+          </template>
+          <template v-if="filter.type === 'tree-select'">
+            <tree-select
+              v-model="options.params[filter.key]"
+              :class="filter.className || 'u-width--xs'"
+              :schema="filter"
+              size="small"
+              @change="onChange"
+            />
+          </template>
           <template v-if="filter.type === 'switch'">
             <span class="c-sibling-item">
               {{ filter.placeholder }}

+ 4 - 0
src/scss/bem/_component.scss

@@ -258,6 +258,10 @@
     background-color: #f4f7fb;
   }
 
+  .el-table__header th.el-table__cell {
+    background-color: #f4f7fb;
+  }
+
   .el-table__header-wrapper {
     flex: none;
   }

+ 3 - 0
src/views/device/index.vue

@@ -67,6 +67,9 @@ export default {
             { value: 0, label: '未签约' },
             { value: 1, label: '已签约' }
           ] },
+          { key: 'serialNumbe', type: 'search', placeholder: 'sn' },
+          { key: 'mac', type: 'search', placeholder: 'mac' },
+          { key: 'address', type: 'search', placeholder: '地址' },
           { key: 'name', type: 'search', placeholder: '设备名称' },
           { type: 'refresh' }
         ],

+ 5 - 1
src/views/marketing/merchant/index.vue

@@ -95,6 +95,9 @@ export default {
         filters: [
           { key: 'name', type: 'search', placeholder: '门店名称' },
           { key: 'personName', type: 'search', placeholder: '门店负责人' },
+          { key: 'personPhone', type: 'search', placeholder: '手机号' },
+          { key: 'address', type: 'search', placeholder: '地址' },
+          { key: 'code', type: 'search', placeholder: 'code' },
           { type: 'refresh' }
         ],
         cols: [
@@ -107,7 +110,8 @@ export default {
           { prop: 'region', label: '省区' },
           { prop: 'serviceName', label: '服务商' },
           { prop: 'servicePerson', label: '服务商联系人', width: 100, align: 'center' },
-          { prop: 'servicePhone', label: '服务商电话', width: 100, align: 'center' },
+          { prop: 'servicePhone', label: '服务商电话', align: 'center' },
+          { prop: 'code', label: 'code', width: 100, align: 'center' },
           { label: '门店认证状态', type: 'tag', render: ({ authStatus }) => authStatus
             ? {
               type: 'danger',

+ 2 - 0
src/views/realm/assign/Device.vue

@@ -17,6 +17,7 @@
 </template>
 
 <script>
+import { getDepartments } from '@/api/user'
 import {
   getBoundDevices,
   getDevices,
@@ -67,6 +68,7 @@ export default {
         list: this.getDevices,
         condition: { isFullDisplay: 0 },
         filters: [
+          { key: 'parentOrg', type: 'tree-select', remote: getDepartments, value: 'path', label: 'name', placeholder: '请选择部门' },
           { key: 'isFullDisplay', type: 'select', options: [
             { value: 0, label: '未分配' },
             { value: 1, label: '全部' }