index.vue 6.01 KB
<style>
.eagle-search {
  padding: 0px;
}
.eagle-search__btn-col {
  text-align: right;
}
</style>

<template>
  <el-form class="eagle-search" ref="search" :model="model" v-bind="{ size: 'small', 'label-width': '90px', ...formProps }">
    <el-row :gutter="15">
      <template v-for="(item, index) in list">
        <el-col v-if="bindItemVisible(item.visible)" v-show="!(collapse && index > visibleColNum - 2)" :key="index + 'data'" :span="!item.span ? span : item.span">
          <el-form-item :label="item.label" :label-width="item.label ? undefined : item.labelWidth || '0px'" :prop="item.key" :rules="item.rules">
            <el-tooltip :disabled="!item.tip" v-bind="bindItemTip(item.tip)">
              <slot v-if="$scopedSlots[item.key] || $slots[item.key]" :name="item.key" :model="model" :value="model[item.key]" v-bind="item"></slot>
              <component v-else :is="item.type || 'el-input'" v-model="model[item.key]" v-bind="bindItemProps(item)" v-on="bindItemEvent(item)" :style="bindItemStyle(item.style)"></component>
            </el-tooltip>
          </el-form-item>
        </el-col>
      </template>
      <el-col :span="list.length >= visibleColNum ? collapse ? span : 24 : span" class="eagle-search__btn-col">
        <slot v-if="$scopedSlots['button-group'] || $slots['button-group']" name="button-group"
          :model="model" :collapse="collapse" :doSearch="handleSearch" :doReset="handleReset" :doCollapse="handleCollapse"
        ></slot>
        <el-button-group v-else>
          <el-button size="small" type="primary" :loading="searching" @click="handleSearch" icon="el-icon-search">{{ i18n('eagle.search.search') || '查询' }}</el-button>
          <el-button size="small" @click="handleReset">{{ i18n('eagle.search.reset') || '重置' }}</el-button>
          <el-button size="small" v-if="list.length > visibleColNum - 1" :icon="collapse ? 'ios-arrow-down' : 'ios-arrow-up'" @click="handleCollapse">
            {{ collapse ? i18n('eagle.search.unfold') ||  '展开' : i18n('eagle.search.fold') || '收起' }}
          </el-button>
        </el-button-group>
      </el-col>
    </el-row>
  </el-form>
</template>

<script>
export default {
  name: 'Search',
  props: {
    // 用于实例化本组件绑定v-model的值
    value: {
      type: Object,
      default: () => {
        return {};
      }
    },
    // 配置列表
    list: {
      type: Array,
      required: true
    },
    // 提交加载状态
    searching: Boolean,
    // 表单参数
    formProps: {
      type: Object,
      default() { return {} }
    },
    // 表单项占位
    span: {
      type: Number,
      default: 6
    },
    // 表单折叠情况下显示数量
    showNumber: Number,
  },
  data() {
    return {
      // 编辑器表单模型
      model: {},
      // 表单折叠状态
      collapse: true,
    };
  },
  created() {
    // 初始化表单模型
    this.initModel(this.list);
  },
  mounted() {
    this.setModelValue(this.value, true);
  },
  computed: {
    // 配置列表键值对形式
    listKeySet() {
      let result = {};
      this.list.forEach(item => {
        result[item.key] = item;
      });
      return result;
    },
    visibleColNum() {
      return this.showNumber ? this.showNumber + 1 : 24 / this.span;
    }
  },
  watch: {
    // 组件外部v-model值更新后同步刷新model
    value(val) {
      this.setModelValue(val);
    },
    // 配置列表有改动时初始化表单模型
    list(value) {
      this.initModel(value);
    },
    model: {
      handler(val) {
        this.$emit("input", val);
        this.$emit("change", val);
      },
      deep: true
    }
  },
  methods: {
    // 设置表单值
    setModelValue(value, isInit) {
      if (isInit) {
        Object.keys(this.listKeySet).forEach(key => {
          this.model[key] = this.listKeySet[key] ? this.listKeySet[key].default : undefined;
        });
        this.$emit("input", this.model);
        this.$emit("change", this.model);
      } else {
        Object.keys(this.model).forEach(key => {
          this.model[key] = value ? value[key] : undefined;
        });
      }
    },
    // 绑定提示组件参数
    bindItemTip(tip) {
      if (typeof tip === 'string') {
        return { content: tip, effect: 'light' };
      } else if (typeof tip === 'object') {
        return tip;
      } else {
        return {};
      }
    },
    // 绑定组件事件
    bindItemEvent(item) {
      if (item.on) {
        if (typeof item.on === 'function') {
          return item.on(this.model);
        } else {
          return item.on
        }
      } else {
        return undefined
      }
    },
    // 初始化表单模型
    initModel(list) {
      list.forEach(item => {
        this.$set(this.model, item.key, item.default || undefined)
      });
    },
    // 绑定组件v-if状态
    bindItemVisible(visible = true) {
      let result = visible;
      if (typeof visible === 'function') {
        result = visible(this.model);
      }
      return result;
    },
    // 绑定组件参数
    bindItemProps(item) {
      const { props = {} } = item;
      let result = { ...props };
      Object.keys(result).forEach(key => {
        if (typeof result[key] === 'function') {
          result[key] = result[key](this.model);
        }
      });
      return result;
    },
    // 绑定组件样式
    bindItemStyle(style = {}) {
      return {
        width: "100%",
        ...style
      };
    },
    // 点击确定提交表单的操作
    handleSearch() {
      this.$refs.search.validate(valid => {
        if (valid) {
          const result = JSON.parse(JSON.stringify(this.model));
          this.$emit("search", result);
        }
      });
    },
    // 重置表单
    handleReset() {
      Object.keys(this.model).forEach(key => {
        this.model[key] = this.listKeySet[key] ? this.listKeySet[key].default : undefined;
      });
      this.$nextTick(() => {
        this.$refs.search.clearValidate();
      });
      this.$emit('reset');
    },
    // 折叠表单
    handleCollapse() {
      this.collapse = !this.collapse;
    }
  }
};
</script>