封装 mysearch 组件

<template>
  <div class="mysearch">
    <el-form
      v-bind="$attrs"
      v-on="$listeners"
      :model="formmodel"
      :inline="inline"
      ref="mysearch"
      :rules="rules"
      :label-width="$attrs['label-width']||calclabelwidth"
    >
      <template v-for="(item, index) in formconfig">
        <template v-if="index < showlen">
          <el-form-item
            :label="item.label+':'"
            :prop="item.prop"
            style="margin:10px 0 20px"
            :key="index+item.label"
          >
            <!--自定义render-->
            <template v-if="item.render">
              <component
                :is="'renderComponent'"
                :value="formmodel[item.prop]"
                :input="e => formmodel[item.prop] = e"
                v-bind="{ ...item }"
              ></component>
            </template>
            <!--自定义插槽-->
            <template v-else-if="item.type==='custom'">
              <slot :name="item.slot" :row="{ ...item, formmodel, index }" />
            </template>

            <!--下拉框-->
            <template v-else-if="item.type === 'select'">
              <el-select
                v-bind="item.attrs"
                v-model="formmodel[item.prop]"
                v-on="getlisteners(item)"
              >
                <el-option
                  v-for="(sitem, index) in getOptions(item)"
                  :key="index"
                  :label="sitem[item.optionlabel||'text']"
                  :value="sitem[item.optionvalue||'value']"
                ></el-option>
              </el-select>
            </template>
            <!--component-->
            <template v-else-if="item.type">
              <myitem
                v-bind="getattrs(item)"
                v-on="getlisteners(item)"
                v-model="formmodel[item.prop]"
              ></myitem>
            </template>
          </el-form-item>
        </template>
      </template>
      <div class="mysearch_btns">
        <el-button @click="toSearch" size="mini" type="primary">查询</el-button>
        <el-button @click="toRest" size="mini">重置</el-button>
        <el-link
          v-if="formconfig.length > showlen"
          type="primary"
          :underline="false"
          style="margin-left:10px"
          @click="searchMoreShow = !searchMoreShow"
        >{{ searchMoreShow ? "收起 " : "更多" }}</el-link>
      </div>
      <template v-if="searchMoreShow">
        <div :class="{ moreQuerys: zindex }" :style="{'width':'100%'}">
          <template v-for="(item, index) in formconfig">
            <template v-if="index >= showlen">
              <!-- :style="{width: item.width +'%','margin-right':0}" -->
              <el-form-item
                :label="item.label+':'"
                :prop="item.prop"
                :key="index+item.label"
                :style="{'margin-right':0}"
              >
                <!--自定义render-->
                <template v-if="item.render">
                  <component
                    :is="'renderComponent'"
                    :value="formmodel[item.prop]"
                    :input="e => formmodel[item.prop] = e"
                    v-bind="{ ...item }"
                  ></component>
                </template>
                <!--自定义插槽-->
                <template v-else-if="item.type==='custom'">
                  <slot :name="item.slot" :row="{ ...item, formmodel, index }" />
                </template>

                <!--下拉框-->
                <template v-else-if="item.type === 'select'">
                  <el-select
                    v-bind="item.attrs"
                    v-model="formmodel[item.prop]"
                    v-on="getlisteners(item)"
                  >
                    <el-option
                      v-for="(sitem, index) in getOptions(item)"
                      :key="index"
                      :label="sitem[item.optionlabel||'text']"
                      :value="sitem[item.optionvalue||'value']"
                    ></el-option>
                  </el-select>
                </template>
                <!--component-->
                <template v-else-if="item.type">
                  <myitem
                    v-bind="getattrs(item)"
                    v-on="getlisteners(item)"
                    v-model="formmodel[item.prop]"
                  ></myitem>
                </template>
              </el-form-item>
            </template>
          </template>
        </div>
      </template>
    </el-form>
  </div>
</template>

<script>
// 邮箱的正则校验
const validateEmail = (rule, value, callback) => {
  if (value) {
    var email =
      /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
    if (!email.test(value)) {
      callback(new Error("邮箱地址格式不正确"));
    } else {
      callback();
    }
  } else {
    //可以为空
    callback();
  }
};

// url地址的正则校验
const validateUrl = (rule, value, callback) => {
  if (value != "") {
    var Url =
      /^((ht|f)tps?):\/\/([\w-]+(\.[\w-]+)*\/?)+(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?$/;
    if (!Url.test(value)) {
      callback(new Error("URL地址格式不正确"));
    } else {
      callback();
    }
  }
};

// 电话号码的正则校验
const validateTel = (rule, value, callback) => {
  if (value != "") {
    var tel = /^1[3456789]\d{9}$/;
    if (!tel.test(value)) {
      callback(new Error("电话号码格式不正确"));
    } else {
      callback();
    }
  }
};

// 身份证号码的校验规则
const validateIdCard = (rule, value, callback) => {
  if (value != "") {
    var IdCard =
      /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{7}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/;
    if (!IdCard.test(value)) {
      callback(new Error("身份证号码格式不正确"));
    } else {
      callback();
    }
  }
};

// 日期校验规则
const validateDate = (rule, value, callback) => {
  if (value != "") {
    var Date =
      /^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/;
    if (!Date.test(value)) {
      callback(new Error("日期格式不正确"));
    } else {
      callback();
    }
  }
};

// 数字校验
const validateNum = (rule, value, callback) => {
  if (!value || isNaN(value)) {
    callback(new Error("数字格式不正确"));
  } else {
    callback();
  }
};

// 时间校验规则
const validateTime = (rule, value, callback) => {
  if (value != null && value != "") {
    var flag = /^([0-1][0-9]|2[0-3]):([0-5][0-9])$/;
    if (!flag.test(value)) {
      callback(new Error("时间格式不正确,格式为  HH:MM"));
    } else {
      callback();
    }
  }
};

// 自定义校验规则
const validateCustom = (val) => {
  return (rule, value, callback) => {
    if (value != null && value != "") {
      var flag = new RegExp(val.patternStr);
      if (!flag.test(value)) {
        callback(new Error(String(val.errorMessage)));
      } else {
        callback();
      }
    }
  };
};

// 长度校验
const min = (val) => {
  return (rule, value, callback) => {
    if (value != null && value != "") {
      if (val.min && val.min > value.length) {
        callback(new Error(`长度下限为 ${val.min} 个字符`));
      } else {
        callback();
      }
    } else {
      callback(new Error(`长度下限为 ${val.min} 个字符`));
    }
  };
};

const max = (val) => {
  return (rule, value, callback) => {
    if (value != null && value != "") {
      if (val.max && val.max < value.length) {
        callback(new Error(`长度上限为 ${val.max} 个字符`));
      } else {
        callback();
      }
    } else {
      callback(new Error(`长度上限为 ${val.max} 个字符`));
    }
  };
};

const regExpFn = {
  email: validateEmail,
  url: validateUrl,
  phone: validateTel,
  identity: validateIdCard,
  date: validateDate,
  number: validateNum,
  timeEmptyAble: validateTime,
  validateCustom: validateCustom,
  min: min,
  max: max,
};

const renderComponent = {
  functional: true,
  props: ["value"],
  render(h, ctx) {
    const { render, attrs, input: handleInput } = ctx.data.attrs;
    return render(h, {
      attrs: {
        ...attrs,
        value: ctx.props.value,
      },
      on: {
        input(e) {
          // handleInput(e);
        },
      },
    });
  },
};
export default {
  inheritAttrs: false,
  name: "mysearch",
  components: { renderComponent },
  props: {
    // 设置更多搜索是否为悬浮,true为悬浮,默认false不悬浮
    zindex: {
      type: Boolean,
      default: true,
    },
    selectUpdate: {
      type: Object,
      default: () => ({}),
    },
    defaultparam: { type: Object, default: () => ({}) },
    showlen: {
      type: Number,
      default: 2,
    },
    inline: {
      type: Boolean,
      default: true,
    },
    formmodel: {
      type: Object,
      default: () => ({}),
    },
    formconfig: {
      type: Array,
      default: () => [],
    },
  },
  data() {
    return {
      result: {},
      rules: {},
      searchMoreShow: false,
    };
  },
  watch: {
    formconfig: {
      handler(val) {
        this.generateRules();
      },
    },
  },
  computed: {
    calclabelwidth() {
      let width = 100;
      let len = 2;
      if (Array.isArray(this.formconfig) && this.formconfig.length) {
        let lenlist = this.formconfig.map((item) => {
          if (typeof item.label === "string") {
            return item.label.length;
          } else {
            return 2;
          }
        });
        len = Math.max.apply(null, lenlist);
      }

      width =
        parseFloat(len * 16 + 30) > parseFloat(width) ? len * 16 + 30 : width;
      return width + "px";
    },
  },
  methods: {
    toSearch() {
      this.result = JSON.parse(JSON.stringify(this.formmodel));
      this.$emit("search", this.result);
    },
    toRest() {
      this.result = JSON.parse(JSON.stringify(this.defaultparam));
      this.$emit("search", this.result, "reset");
    },
    getOptions(item) {
      if (item.optkey) {
        return this.selectUpdate[item.optkey];
      } else {
        return this.selectUpdate[item.prop] || item.options || [];
      }
    },
    //设置下拉
    setOptions() {
      Object.keys(this.selectUpdate).forEach((v) => {
        const index = this.formconfig.findIndex((k) => k.prop === v);
        if (index !== -1) {
          this.$set(this.formconfig[index], "options", this.selectUpdate[v]);
        }
        const index2 = this.formconfig.findIndex((k) => k.optkey === v);
        if (index2 !== -1) {
          this.$set(this.formconfig[index2], "options", this.selectUpdate[v]);
        }
      });
    },
    // 查询系统集成的自定规则
    ergExtFunc(val) {
      if (regExpFn[val]) {
        return {
          trigger: "blur",
          validator: regExpFn[val],
        };
      }
    },

    // 根据传进来的正则规则生成符合el-form的校验规则
    regExpCustom(val) {
      // console.log(val);
      // if (val.patternStr && val.errorMessage) return;
      if (val.type == "select" || val.type == "tree") {
        return {
          trigger: "change",
          validator: regExpFn.validateCustom(val),
        };
      }
      // console.log(regExpFn.validateCustom(val));
      return {
        trigger: "blur",
        validator: regExpFn.validateCustom(val),
      };
    },

    generateRules() {
      // 生成校验规则
      this.rules = {};
      this.formconfig.forEach((v) => {
        const model = [];
        const item = {};
        const origin = {};
        // 必填校验
        if (v.required) {
          if (v.type == "select" || v.type == "tree") {
            item.required = true;
            item.message = v.message || `${v.label}必填`;
            item.trigger = "change";
            model.push(item);
          } else if (v.type == "selectInput") {
            model.push({
              required: true,
              message: `${v.label}必填`,
              trigger: "change",
            });
          } else {
            item.required = true;
            item.message = v.message || `${v.label}必填`;
            item.trigger = "blur";
            model.push(item);
          }
        }

        // 长度校验
        if (v.min || v.max) {
          if (v.min) {
            item.min = v.min;
            item.message = `长度下限 ${item.min} 个字符`;
          }
          if (v.max) {
            item.max = v.max;
            item.message = `长度上限 ${item.max} 个字符`;
          }
          if (v.min && v.max) {
            item.message = `长度在 ${item.min} 到 ${item.max} 个字符`;
          }
          item.trigger = "blur";
          model.push(item);
        }

        if (typeof v.validate == "string") {
          const validateList = v.validate.split("|");
          // console.log(validateList);
          validateList.forEach((validate) => {
            // 以下皆为系统自定义集成的规则
            if (validate == "date") {
              model.push(this.ergExtFunc("date"));
            }
            if (validate == "email") {
              model.push(this.ergExtFunc("email"));
            }
            if (validate == "url") {
              model.push(this.ergExtFunc("url"));
            }
            if (validate == "phone") {
              model.push(this.ergExtFunc("phone"));
            }
            if (validate == "identity") {
              model.push(this.ergExtFunc("identity"));
            }
            if (validate == "number") {
              model.push(this.ergExtFunc("number"));
            }
            if (validate == "timeEmptyAble") {
              model.push(this.ergExtFunc("timeEmptyAble"));
            }
            // 以下为用户添加的自定义校验规则
            if (validate == "pattern") {
              model.push(this.regExpCustom(v));
            }
          });
        }

        // 自定义校验规则
        if (v.validate && typeof v.validate != "string") {
          if (v.type == "select" || v.type == "tree") {
            origin.trigger = "change";
            origin.validator = v.validate;
            model.push(origin);
          } else {
            origin.trigger = "blur";
            origin.validator = v.validate;
            model.push(origin);
          }
        }
        if (model.length > 0) {
          this.$set(this.rules, v.prop, model);
        }

        if (v.type === "selectDate") {
          v.children.forEach((j) => {
            if (j.required) {
              item.required = true;
              item.message = `${v.label}必填`;
              item.trigger = "change";
              model.unshift(item);
              this.$set(this.rules, j.prop, model);
            }
          });
        }
      });
      this.$nextTick(() => {
        this.$refs.mysearch.clearValidate();
      });
    },
    //继承el-form 方法
    extendMethod() {
      const refMethod = Object.entries(this.$refs["mysearch"]);
      for (const [key, value] of refMethod) {
        if (!(key.includes("$") || key.includes("_"))) {
          this[key] = value;
        }
      }
    },

    getattrs(item) {
      let obj = item.attrs || {};
      if (!obj.placeholder) {
        let prevtext = "请输入";
        if (item.type === "select") {
          prevtext = "请选择";
        }
        obj.placeholder = prevtext + item.label;
      }
      if (typeof item.disabled === "boolean") {
        obj.disabled = item.disabled;
      }
      let component = "";
      switch (item.type) {
        case "input":
        case "search":
        case "text":
          component = "el-input";
          break;
        case "textarea":
          component = "el-input";
          obj.type = "textarea";
          obj.rows = parseInt(obj.rows) || 3;
          obj.resize = "none";
          break;
        case "switch":
          component = "el-switch";
          obj.activeColor = obj.activeColor || "rgb(64,158,255)";
          obj.inactiveColor = obj.inactiveColor || "#ff4949";
          break;
        case "date":
          component = "el-date-picker";
          obj.type = "date";
          obj.format = "yyyy-MM-dd";
          obj.valueFormat = "yyyy-MM-dd";
          break;
        case "year":
          component = "el-date-picker";
          obj.type = "year";
          obj.format = "yyyy";
          obj.valueFormat = "yyyy";
          break;
        case "yearmonth":
          component = "el-date-picker";

          obj.type = "month";
          obj.format = "yyyy-MM";
          obj.valueFormat = "yyyy-MM";
          break;
        case "datetimerange":
          component = "el-date-picker";
          obj.type = "datetimerange";
          obj.rangeSeparator = "至";
          obj.format = "yyyy-MM-dd";
          obj.valueFormat = "yyyy-MM-dd";

          break;

        default:
          component;
          break;
      }

      if (!obj.component) {
        obj.component = component;
      }
      return obj;
    },
    getlisteners(item) {
      return item.event || {};
    },
  },
  mounted() {
    this.extendMethod();
    // this.setOptions();
  },
  created() {
    this.generateRules();
    //  this.$emit('update:model', this.model);
  },
};
</script>
<style lang="scss">
.mysearch_btns {
  display: inline-block;
  line-height: 56px;
  margin-left: 10px;
}
.el-form-item__content {
  width: 210px;
}

.moreQuerys {
  position: absolute;
  z-index: 5;
  background: rgb(255, 255, 255);
  margin-top: -5px;
  padding-top: 15px;
  border: 1px solid rgb(224, 224, 224);
  left: 0px;
  box-shadow: rgba(82, 82, 82, 0.2) 0px 3px 10px;
}
</style>
<mysearch :selectUpdate="selectUpdate"  :formconfig="formconfig" :formmodel="formmodel" @search='search'></mysearch>
search(val,type){
      console.log(val,type);
    }
formmodel: {
        // date: "",
        // name: "",
        // address: "",
        // number: "",
        // scholl: "",
      },
      formconfig: [
         {
          type: "text",

          prop: "date",
          label: "日期",
          width: 50,
          event: {
            change: (a, b, c, d) => {
              console.log(a, b, c, d);
            },
          },
        },
         {
          type: "text",

          prop: "date",
          label: "日期",
          width: 50,
          event: {
            change: (a, b, c, d) => {
              console.log(a, b, c, d);
            },
          },
        },
         {
          type: "text",

          prop: "date",
          label: "日期",
          width: 50,
          event: {
            change: (a, b, c, d) => {
              console.log(a, b, c, d);
            },
          },
        },
        {
          type: "text",

          prop: "date",
          label: "日期",
          width: 50,
          event: {
            change: (a, b, c, d) => {
              console.log(a, b, c, d);
            },
          },
        },
        {
          type: "text",
          prop: "name",
          label: "名称",

          width: 50,
          attrs: {
            placeholder: "请填写名称",
          },
        },
        {
          type: "select",
          prop: "address",
          label: "地址",
          width: 50,
          attrs: {
            placeholder: "请选择地址",
            style: {
              width: "100%",
            },
          },
          optionlabel: "11",
          optionvalue: "777",

          // options: {
          //   // data: this.tableData,
          //   // extraProps: {
          //   //   value: "address",
          //   //   label: "address",
          //   // },
          // },
        },
        {
          type: "text",
          slot: "number",
          width: 50,
          label: "编号",
          attrs: {
            placeholder: "请输入编号",
          },
        },
        {
          type: "text",
          prop: "scholl",
          width: 50,
          label: "毕业学校",
          attrs: {
            placeholder: "请输入毕业学校",
          },
          // render: (h, props) =>
          //   h("el-input", {
          //     ...props,
          //   }),
        },
      ],
posted @ 2023-07-09 15:14  7c89  阅读(2)  评论(0编辑  收藏  举报