天天看點

vue封裝搜尋元件

封裝搜尋元件,優化代碼量,減少備援

<template>
  <div v-if="!$_.isEmpty(searchData)" class="search-box">
    <slot name="before" />
    <div v-for="(item, idx) in searchDataIsVisible" :key="idx" class="form">
      <div v-if="item.type === 'select'" class="select">
        <span class="text">{{ item.title }}</span>
        <el-select
          v-model="query[item.model]"
          :style="{ width: item.width }"
          filterable
          :clearable="!item.clearable"
          :loading="item.loading"
          :remote="!!item.callback"
          :remote-method="item.callback ? q => remoteMethod(q, item) : null"
          @change="value => onSelectClear(value, item)"
        >
          <!-- <el-option
            v-for="i in item.enumType
              ? $enums[item.enumType].allList()
              : item.option"
            :key="i.value"
            :label="i.label"
            :value="i.value"
          /> -->
          <el-option
            v-for="i in item.option"
            :key="i.value"
            :label="i.label"
            :value="i.value"
          />
        </el-select>
      </div>
      <div v-if="item.type === 'cascader'" class="cascader">
        <span class="text">{{ item.title }}</span>
        <el-cascader
          v-model="item.model"
          :style="{ width: item.width }"
          :options="item.option"
          :props="item.props"
          collapse-tags
          clearable
          change-on-select
          @change="value => cascaderChange(value, item)"
        />
      </div>
      <div v-if="item.type === 'dateSection'" class="date-section">
        <span class="text">{{ item.title }}</span>
        <el-date-picker
          v-model="date"
          class="date input"
          :type="item.dateType"
          align="right"
          unlink-panels
          start-placeholder="開始日期"
          end-placeholder="結束日期"
          :picker-options="pickerOptions"
          @change="value => dateChange(value, item)"
        />
      </div>
      <div v-if="item.type === 'date'" class="date">
        <span class="text">{{ item.title }}</span>
        <el-date-picker
          v-model="item.initialDate"
          :type="item.dateType"
          :format="
            item.dateType === 'month'
              ? 'yyyy-MM'
              : item.dateType === 'year'
                ? 'yyyy'
                : 'yyyy-MM-dd'
          "
          class="date"
          :picker-options="item.noShortcut ? pickerOptions1 : pickerOptions"
          placeholder="選擇時間"
          @change="value => dateSingeChange(value, item)"
        />
      </div>
      <div v-if="item.type === 'input'" class="input">
        <span class="text">{{ item.title }}</span>
        <el-input
          v-model="query[item.modelName]"
          :placeholder="item.placeholder"
          @keyup.enter.native="emitSearchChange"
        >
          <el-button
            slot="append"
            icon="el-icon-search"
            @click="emitSearchChange"
          />
          <!--<i @click="$search(table)" slot="suffix" class="el-input__icon el-icon-search"></i>-->
        </el-input>
      </div>
    </div>
    <span class="ctrl-btn">
      <slot name="after" />
    </span>
  </div>
</template>

<script>
export default {
  props: {
    searchData: {
      type: Array,
      default() {
        return []
      }
    },
    query: {
      type: Object,
      default() {
        return {}
      }
    }
  },
  data() {
    return {
      pickerOptions1: {
        disabledDate(date) {
          // disabledDate 文檔上:設定禁用狀态,參數為目前日期,要求傳回 Boolean
          return date.getTime() >= Date.now()
        }
      },
      pickerOptions: {
        disabledDate(date) {
          // disabledDate 文檔上:設定禁用狀态,參數為目前日期,要求傳回 Boolean
          return date.getTime() >= Date.now()
        },
        shortcuts: [
          {
            text: '最近一個月',
            onClick(picker) {
              const end = new Date()
              const start = new Date()
              start.setTime(
                new Date(new Date().setMonth(new Date().getMonth() - 1))
              )
              picker.$emit('pick', [start, end])
            }
          },
          {
            text: '最近三個月',
            onClick(picker) {
              const end = new Date()
              const start = new Date()
              start.setTime(
                new Date(new Date().setMonth(new Date().getMonth() - 3))
              )
              picker.$emit('pick', [start, end])
            }
          },
          {
            text: '最近六個月',
            onClick(picker) {
              const end = new Date()
              const start = new Date()
              start.setTime(
                new Date(new Date().setMonth(new Date().getMonth() - 6))
              )
              picker.$emit('pick', [start, end])
            }
          }
        ]
      }
    }
  },
  computed: {
    searchDataIsVisible() {
      return this.searchData.filter(t => !t.hide)
    },
    // date() {
    //   const arr = []
    //   this.searchData.forEach(e => {
    //     e.modelName &&
    //       Array.isArray(e.modelName) &&
    //       e.modelName.forEach(i => {
    //         arr.push(this.query[i])
    //       })
    //   })
    //   return arr || []
    // },
    date: {
      get: function() {
        const arr = []
        this.searchData.forEach(e => {
          e.modelName &&
            Array.isArray(e.modelName) &&
            e.modelName.forEach(i => {
              arr.push(this.query[i])
            })
        })
        return arr || []
      },
      set: function(val) {
        this.searchData.forEach(e => {
          e.modelName &&
            Array.isArray(e.modelName) &&
            e.modelName.forEach((i, idx) => {
              if (val) {
                if (idx === 0) {
                  this.query[i] = this.$dayjs(val[0]).format(
                    'YYYY-MM-DD 00:00:00'
                  )
                } else {
                  this.query[i] = this.$dayjs(val[1]).format(
                    'YYYY-MM-DD 23:59:59'
                  )
                }
              }
            })
        })
      }
    }
  },
  created() {
    this.initOptions()
  },
  methods: {
    // select 遠端搜尋回調
    async remoteMethod(q, item) {
      const setOption = newOpt => this.$set(item, 'option', newOpt)
      const setLoading = v => this.$set(item, 'loading', v)
      item.callback(q, { setOption, setLoading })
    },
    initOptions() {
      this.searchData.forEach(async item => {
        if (item.api) {
          // eslint-disable-next-line no-useless-catch
          try {
            this.$set(item, 'loading', true)
            const query = this.$_.cloneDeep(item.query) || {}
            const res = await item.api(query)
            this.$set(item, 'loading', false)
            let data = null
            if (res instanceof Array) {
              data = res
            }
            // let data = res.data.data
            // if (data instanceof Array) {
            if (item.type === 'tree') {
              this.$set(item, 'option', data)
            } else if (item.type === 'select') {
              this.$set(
                item,
                'option',
                data.map(obj => {
                  return {
                    value: obj[item.keyValueName ? item.keyValueName[0] : 'id'],
                    label:
                      obj[item.keyValueName ? item.keyValueName[1] : 'name']
                  }
                })
              )
            }
            // }
          } catch (e) {
            throw e
          }
        }
      })
    },
    emitSearchChange() {
      this.$emit('on-search-change', this.query)
    },
    onSelectClear(val, item) {
      if (!val) {
        this.query[item.model] = ''
      }
      if (this.query.clone) {
        this.query[this.query.clone1] = this.$_.cloneDeep(this.query.startTime)
        this.query[this.query.clone2] = this.$_.cloneDeep(this.query.endTime)
      }
      this.emitSearchChange()
    },
    // cascader 值改變的時候
    cascaderChange(val, item) {
      if (item.props.multiple) {
        const arr = []
        for (let i = 0; i < val.length; i++) {
          arr.push(val[i][val[i].length - 1])
        }
        this.query[item.modelName] = arr
      } else {
        this.query[item.modelName] = val
      }
      this.emitSearchChange()
    },
    // 日期選擇控件切換的回調
    dateChange(val, item) {
      //
      if (val === null) {
        this.query[item.modelName[0]] = this.$dayjs().format(
          'YYYY-MM-DD 00:00:00'
        )
        this.query[item.modelName[1]] = this.$dayjs().format(
          'YYYY-MM-DD 23:59:59'
        )
      } else {
        this.query[item.modelName[0]] = this.$dayjs(val[0]).format(
          'YYYY-MM-DD 00:00:00'
        )
        this.query[item.modelName[1]] = this.$dayjs(val[1]).format(
          'YYYY-MM-DD 23:59:59'
        )
      }
      if (this.query.userChange) {
        this.query.sortApi = 'listStaticSort'
      }
      if (this.query.clone) {
        this.query[this.query.clone1] = this.$_.cloneDeep(
          this.query[item.modelName[0]]
        )
        this.query[this.query.clone2] = this.$_.cloneDeep(
          this.query[item.modelName[1]]
        )
      }
      this.emitSearchChange()
    },
    // 日期單選控件切換的回調
    dateSingeChange(val, item) {
      // this.query[item.model] = val
      if (item.onlyYear) {
        if (!val) {
          this.query[item.model] = null
          this.emitSearchChange()
          return
        }
        this.query[item.model] = this.$dayjs(val).format('YYYY')
        this.emitSearchChange()
        return
      }
      if (val === null) {
        // let date = new Date()
        // this.query[item.model] = this.$dayjs(date).format('YYYY-MM-DD HH:mm:ss')
        this.query[item.model] = null
      } else {
        this.query[item.model] = this.$dayjs(val).format('YYYY-MM-DD HH:mm:ss')
      }
      this.emitSearchChange()
    }
  }
}
</script>

<style lang="scss" scoped>
.search-box {
  padding: 0 0 20px 0;
  min-width: 806px;
  .ctrl-btn {
    display: inline-block;
    margin-top: 38px;
  }
  .item {
    margin-top: 10px;
  }
  .text {
    display: block;
    margin-left: 5px;
    margin-bottom: 5px;
    font-size: 12px;
    font-weight: bold;
    color: #666;
  }
  .form {
    display: inline-block;
    margin-right: 10px;
    margin-top: 10px;
    margin-bottom: 10px;
    vertical-align: top;
    // float: left;
  }
  .date {
    width: 260px !important;
  }
  .el-select {
    width: 160px;
    display: block;
    display: block;
    .el-input__inner {
      padding-right: 30px !important;
    }
  }
  .el-cascader {
    width: 160px;
  }
  .el-date-editor .el-range-separator {
    line-height: 28px !important;
  }
  .input {
    width: 210px;
  }
}
</style>
           

繼續閱讀