vue(elementUI)项目运用的工具函数

177 阅读4分钟
/*
 * @Description: 自定义公共方法 插件引入
 */
import Vue from 'vue'
let vm = new Vue({});


//发送错误报告
const errorHandler = (error,vm,info)=>{
  console.log(error,info);
}
Vue.config.errorHandler = errorHandler;
Vue.prototype.$throw = (error,vm,info)=> errorHandler(error,vm,info);


// 确认框 函数
Vue.prototype.$theConfirm = (config, type) => {
  let { title, content, leftBtn, rightBtn } = config;
  title = title ? title : '提示';
  content = content ? content : '确定如此操作';
  leftBtn = leftBtn ? leftBtn : '确定';
  rightBtn = rightBtn ? rightBtn : '取消';
  return new Promise((resolve, reject) => {
    vm.$confirm(content, title, {
      confirmButtonText: leftBtn,
      cancelButtonText: rightBtn,
      cancelButtonClass: 'el-button--border cancel-Button-Class',
      type: type,
      center: true
    }).then(() => {
      resolve()
    }).catch(() => {
      reject()
    })
  })

}

// 解决传参 [key][0][val]  =>  key[0].val
// 调用示例: $dataTransform(this.addOrEditData, 'buttons');
Vue.prototype.$dataTransform = (object, property) => {
  if (Array.isArray(object[property])) {
    object[property].forEach((val, i) => {
      for (var j in val) {
        object[property + "[" + i + "]." + j] = val[j];
      }
    });
    delete object[property];
  }
  if (object[property] instanceof Object) {
    for (const key in object[property]) {
      if (object[property].hasOwnProperty(key)) {
        const element = object[property][key];
        object[property + "." + key] = element;
      }
    }
    delete object[property];
  }
}

/**
  * @description: 判断数据不存在 或 为空值
  * @param {所有数据类型} data [需要验证的数据]
  * @return: [存在非空false,不存在或是空值true]
  */
Vue.prototype.$dataIsNull = (data) => {
  if (typeof data === "undefined") {
    return true;
  } else if (data instanceof Array) {
    if (data.length === 0) return true;
  } else if (data instanceof Object) {
    if (JSON.stringify(data) === '{}') return true;
  } else if (data === 'null' || data === null || data === 'undefined' || data === '') {
    return true;
  } else {
    return false;
  }
}
/**
  * @description: 用于后台获取的数据应用于页面数据,避免直接赋值带来的属性缺失
  * @param {Object} pageData [页面初始化的数据,与接口相匹配]
  * @param {Object} getData [后台获取的数据,由于未初始化的数据后台不做返回,可能缺失重要属性]
  * @return: [补全必要字段的后台数据]
  */
Vue.prototype.$mergeObject = (pageData, getData) => {
  for (const item in pageData) {
    if (!getData.hasOwnProperty(item)) {
      getData[item] = pageData[item];
    }
  }
  return getData
}

// 日期时间相关方法
Vue.prototype.$date = {
  // 时间格式化
  format: (date, fmt = "yyyy-MM-dd hh:mm:ss") => {
    if (!date || date == null) {
      return date;
    }
    date = new Date(date)
    if (/(y+)/.test(fmt)) {
      fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
    }
    let o = {
      'M+': date.getMonth() + 1,
      'd+': date.getDate(),
      'h+': date.getHours(),
      'm+': date.getMinutes(),
      's+': date.getSeconds()
    };
    let padLeftZero = (str) => {
      return ('00' + str).substr(str.length);
    };
    for (let k in o) {
      if (new RegExp(`(${k})`).test(fmt)) {
        let str = o[k] + '';
        fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));
      }
    }
    return fmt;
  },
  // 验证开始时间 结束时间 的关系
  validator: (start, end, symbol = ">=") => {
    if (start && end) {
      // eslint-disable-next-line no-eval
      if (eval(`${new Date(start).getTime()}${symbol}${new Date(end).getTime()}`)) {
        return false;
      } else {
        return true;
      }
    } else {
      return false;
    }
  },
  /**
    * @description: 计算两天之间相差多少年月日
    * @param {String}  sDate1 [开始日期yyyy-MM-dd]
    * @param {String}  sDate2 [结束日期yyyy-MM-dd]
    * @return: { y: y, m: m, d: d }
    */
  dateDiff: (sDate1, sDate2) => {
    var fixDate = function (sDate) {
      var aD = sDate.split('-');
      for (var i = 0; i < aD.length; i++) {
        aD[i] = fixZero(parseInt(aD[i]));
      }
      return aD.join('-');
    };
    var fixZero = function (n) {
      return n < 10 ? '0' + n : n;
    };
    var fixInt = function (a) {
      for (var i = 0; i < a.length; i++) {
        a[i] = parseInt(a[i]);
      }
      return a;
    };
    var getMonthDays = function (y, m) {
      var aMonthDays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
      // eslint-disable-next-line eqeqeq
      if ((y % 400 == 0) || (y % 4 == 0 && y % 100 != 0)) {
        aMonthDays[2] = 29;
      }
      return aMonthDays[m];
    };
    var y = 0;
    var m = 0;
    var d = 0;
    var sTmp;
    var aTmp;
    sDate1 = fixDate(sDate1);
    sDate2 = fixDate(sDate2);
    if (sDate1 > sDate2) {
      sTmp = sDate2;
      sDate2 = sDate1;
      sDate1 = sTmp;
    }
    var aDate1 = sDate1.split('-');
    aDate1 = fixInt(aDate1);
    var aDate2 = sDate2.split('-');
    aDate2 = fixInt(aDate2);
    //计算相差的年份
    /*aTmp = [aDate1[0]+1,fixZero(aDate1[1]),fixZero(aDate1[2])];
    while(aTmp.join('-') <= sDate2){
      y++;
      aTmp[0]++;
    }*/
    y = aDate2[0] - aDate1[0];
    if (sDate2.replace(aDate2[0], '') < sDate1.replace(aDate1[0], '')) {
      y = y - 1;
    }
    //计算月份
    aTmp = [aDate1[0] + y, aDate1[1], fixZero(aDate1[2])];
    while (true) {
      // eslint-disable-next-line eqeqeq
      if (aTmp[1] == 12) {
        aTmp[0]++;
        aTmp[1] = 1;
      } else {
        aTmp[1]++;
      }
      if (([aTmp[0], fixZero(aTmp[1]), aTmp[2]]).join('-') <= sDate2) {
        m++;
      } else {
        break;
      }
    }
    //计算天数
    aTmp = [aDate1[0] + y, aDate1[1] + m, aDate1[2]];
    if (aTmp[1] > 12) {
      aTmp[0]++;
      aTmp[1] -= 12;
    }
    while (true) {
      // eslint-disable-next-line eqeqeq
      if (aTmp[2] == getMonthDays(aTmp[0], aTmp[1])) {
        aTmp[1]++;
        aTmp[2] = 1;
      } else {
        aTmp[2]++;
      }
      sTmp = ([aTmp[0], fixZero(aTmp[1]), fixZero(aTmp[2])]).join('-');
      if (sTmp <= sDate2) {
        d++;
      } else {
        break;
      }
    }
    return { y: y, m: m, d: d };
  }
}
// 数字相关方法
Vue.prototype.$number = {
  // 时间格式化
  format: (number, decimals, isThousandsSep) => {
    /*
     * 参数说明:
     * number:要格式化的数字
     * decimals:保留几位小数
     * isThousandsSep:是否加入千分位符号
     * */
    number = (number + '').replace(/[^0-9+-Ee.]/g, '');
    // eslint-disable-next-line one-var
    let n = !isFinite(+number) ? 0 : +number,
      prec = !isFinite(+decimals) ? 2 : Math.abs(decimals),
      sep = ',',
      dec = '.',
      s = '',
      toFixedFix = function (n, prec) {
        var k = Math.pow(10, prec);
        return '' + Math.round(n * k) / k;
      };
    // console.log(toFixedFix(n, prec),Math.round(n));
    s = toFixedFix(n, prec).split('.');
    var re = /(-?\d+)(\d{3})/;
    // 判断是否加千位分隔符
    if (isThousandsSep) {
      while (re.test(s[0])) {
        s[0] = s[0].replace(re, "$1" + sep + "$2");
      }
    }
    if ((s[1] || '').length < prec) {
      s[1] = s[1] || '';
      s[1] += new Array(prec - s[1].length + 1).join('0');
    }
    return s.join(dec);
  },
  // 纯数字字符串转为数字 反之 不处理
  parseNumber: (val) => {
    return isNaN(Number(val)) ? val : Number(val)
  }
}
// 文本方法操作
Vue.prototype.$text = {
  // 防止脚本注入 替换script标签
  stripScript: (str) => {
    return str.replace(/<script.*?>.*?<\/script>/ig, '');
  },
  // 取消文本两端的空格
  trim: (str) => {
    return str.replace(/(^\s*)|(\s*$)/g, "");
  }
}
// 数组方法
Vue.prototype.$array = {
  /**
   * @description: 获取数组中每个对象某个key的新集合
   * @param {type}
   * @return:
   */
  returnArrayByKey: (originArr, key) => {
    let arr = [];
    if (Array.isArray(originArr)) {
      originArr.forEach((item) => {
        if (item[key]) arr.push(item[key]);
      });
    }
    return arr;
  }
}
// 对象数组深拷贝
Vue.prototype.$clone = (obj) => {
  let clone = (obj) => {
    if (obj === null) return obj;
    if (typeof obj !== 'object') { return obj; }
    let cloneObj = {};
    switch (obj.constructor) {
      case Array:
        cloneObj = [];
        if (obj.length !== 0) {
          for (let i = 0, len = obj.length; i < len; i++) {
            cloneObj.push(clone(obj[i]));
          }
        }
        break;
      case Object:
        for (var property in obj) {
          cloneObj[property] = typeof obj[property] === 'object' ? clone(obj[property]) : obj[property];
        }
        break;
      case Map:
        cloneObj = new Map();
        obj.forEach((value, key) => {
          cloneObj.set(key, typeof value === 'object' ? clone(value) : value);
        });
        break;
      case Set:
        cloneObj = new Set();
        obj.forEach(value => {
          cloneObj.add(typeof value === 'object' ? clone(value) : value);
        });
        break;
      default:
        for (var property in obj) {
          cloneObj[property] = obj[property].constructor === Object ? clone(obj[property]) : obj[property];
        }
        break;
    }
    return cloneObj;
  }
  return clone(obj)
}
// 获得树形数据ID数组
Vue.prototype.$treeFn = {
  /**
  * @description:  线性数据转化为树
  * @param {Array} originArr [原始数组]
  * @param {Number} originId [初始化的顶级节点id]
  * @param {Object} config [数据配置项]
  * @return:
  */
  toTree: (originArr, originId, config) => {
    const configName = config.name || "name";
    const configPId = config.pId || "pId";
    const configPName = config.pName || "pName";
    const configChildren = config.children || "children";
    const configOriginNode = config.originNode || "根节点";
    let obj = {};
    originArr.forEach((item, index) => {
      obj[item.id] = item
    })
    // let newObj = JSON.parse(JSON.stringify(obj));
    const toTreeFn = (arr, id) => {
      let tree = [];
      let temp = null;
      originArr.forEach((item, index) => {
        item[configPName] = obj[item[configPId]] ? obj[item[configPId]][configName] : configOriginNode;
        if (item[configPId] === id) {
          temp = toTreeFn(arr, item.id);
          if (temp.length > 0) {
            item[configChildren] = temp;
          }
          tree.push(item);
          delete originArr[index];
        }
      })
      return tree;
    }
    return toTreeFn(originArr, originId)
  },
  /**
  * @description:  获取树中  所有节点id
  * @param {Array} originArr [原始数组]
  * @param {Object} config [数据配置项]
  * @return:
  */
  findAllId: (originArr, config) => {
    config = config || "children";
    let arr = [];
    const getId = (data1, arr1) => {
      data1.map((item) => {
        arr1.push(item.id);
        if (item[config]) {
          getId(item[config], arr1)
        }
      })
    }
    getId(originArr, arr);
    return arr
  },
  /**
  * @description:  获取当前节点及其所有父节点 id
  * @param {Array} originArr [原始数组]
  * @param {Number,String} findId [初始化的顶级节点id]
  * @param {Object} config [数据配置项]
  * @return:
  */
  findAllPId: (originArr, findId, config) => {
    if (!findId) return [];
    if (!config) {
      config = {
        children: "children",
        label: "label",
        pId: "pId"
      }
    }
    let { children, pId } = config;
    let idsArr = [];
    let labelArr = [];
    const findNode = (arr, id) => {
      if (!Array.isArray(arr)) return;
      arr.some((item) => {
        if (item.id === id) {
          idsArr.unshift(item.id);
          labelArr.unshift(item[config.label]);
          if (item[pId] !== 0) {
            findNode(originArr, item[pId]);
          };
        }
        if (item[children] && item[children].length !== 0) {
          findNode(item[children], id);
        }
      })
    }
    findNode(originArr, findId);
    // console.log("查找多叉树某节点所有父级id", idsArr);
    return {
      id: idsArr,
      label: labelArr
    };
  },
  /**
  * @description:  通过节点id找到节点数据
  * @param {Array} originArr [原始数组]
  * @param {Number,String} findId [初始化的顶级节点id]
  * @param {Object} config [数据配置项]
  * @return:
  */
  findNodeById: (originArr, findId, config) => {
    if (!findId) return [];
    if (!config) {
      config = {
        children: "children"
      }
    }
    let { children } = config;
    let result = {};
    const findNode = (arr, id) => {
      if (!Array.isArray(arr)) return;
      arr.find((item) => {
        if (item.id === id) {
          result = item;
          return true;
        }
        if (item[children] && item[children].length !== 0) {
          findNode(item[children], id);
        }
      })
    }
    findNode(originArr, findId);
    // console.log("查找多叉树某节点所有父级id", result);
    return result;
  }
}

// 阿拉伯数字转中文大写
Vue.prototype.$capital = (n) => {
  if (!/^(0|[1-9]\d*)(\.\d+)?$/.test(n)) { return "数据非法"; }
  // eslint-disable-next-line one-var
  var unit = "千百拾亿千百拾万千百拾元角分",
    str = "";
  n += "00";
  var p = n.indexOf('.');
  // eslint-disable-next-line curly
  if (p >= 0)
    n = n.substring(0, p) + n.substr(p + 1, 2);
  unit = unit.substr(unit.length - n.length);
  // eslint-disable-next-line curly
  for (var i = 0; i < n.length; i++)
    str += '零壹贰叁肆伍陆柒捌玖'.charAt(n.charAt(i)) + unit.charAt(i);
  return str.replace(/零(千|百|拾|角)/g, "零").replace(/(零)+/g, "零").replace(/零(万|亿|元)/g, "$1").replace(/(亿)万|壹(拾)/g, "$1$2").replace(/^元零?|零分/g, "").replace(/元$/g, "元整");
}

// 过滤函数
Vue.prototype.$filters = {
  /**
   * @description: 过滤字符串
   * @param val {string}  value
   * @param formatArr {Array} 格式化数组   [{value:1 , label: "A"}]
   * @return: 过滤后的值
   */
  string: function (val, formatArr) {
    if (vm.$dataIsNull(val)) return val;
    if (Array.isArray(formatArr)) {
      let obj = formatArr.find((item) => {
        // 判读key 是 id 还是 value
        const key = vm.$dataIsNull(item.id) ? 'value' : 'id';
        // eslint-disable-next-line eqeqeq
        if (item[key] == val || item[key] == val) {
          obj = item;
          return true
        }
      })
      if (!obj) return val;
      if (obj.label) {
        return obj.label
      } else if (obj.name) {
        return obj.name
      } else if (obj.title) {
        return obj.title
      } else if (obj.text) {
        return obj.text
      } else {
        return val
      }
    }
    return val
  },
  /**
   * @description: 过滤时间
   * @param val {string}  value
   * @param formatTxt {string} 格式化类型
   * @return: 过滤后的值
   */
  date: function (val, formatTxt) {
    if (val === undefined || val === null || val === "") return val;
    if (typeof formatTxt !== "string" || formatTxt === "") {
      formatTxt = "yyyy-MM-dd hh:mm:ss"
    }
    return Vue.prototype.$date.format(val, formatTxt)
  },
  /**
   * @description: 过滤数字
   * @param val {string}  value
   * @param formatTxt {string} 格式化类型 number,Boolean  number表示保留几位小数 Boolean表示是否显示千分位分隔符
   * @return: 过滤后的值
   */
  number: function (val, formatTxt) {
    if (val === undefined || val === null || val === "") return val;
    if (typeof formatTxt === "string" && formatTxt !== "") {
      let [n, isTS] = formatTxt.split(",");
      if (isTS === "true") {
        isTS = true;
      } else {
        isTS = false;
      }
      return Vue.prototype.$number.format(val, n, isTS)
    }
    return val;
  },
  /**
   * @description: 过滤地址
   * @param val {string}  value
   * @return: 过滤后的值
   */
  area: function (val) {
    const thisId = Number(val);
    let result = null;
    const parseId = (arr, id) => {
      arr.map((item) => {
        if (item.value === id) {
          result = item.label;
          return item.label;
        }
        if (item.children && item.children.length !== 0) {
          parseId(item.children, id)
        }
      })
    }
    if (isNaN(thisId)) {
      return val
    } else {
      parseId(Map, thisId);
      return result === null ? val : result;
    }
  },
  ellipsisWord: function (str, num) {
    if (!str) return ''
    if (str.length > num) {
      return str.slice(0, num) + '...'
    }
    return str
  }
}

/**
 * @description:  解析图片路径
 * @param {String} path [文件路径]
 * @return:
 */
Vue.prototype.$parseUrl = function (path) {
  return encodeURI(process.env.imgUrl + path);
}

// 文件服务相关操作
Vue.prototype.$file = {
  /**
   * @description: 文件验证器
   * @param file {string} 文件对象(element ui上传工具验证方法传入对象)
   * @param typeArr {array} 文件类型组成的数组 ["jpg", "png"], 不传参表示任意类型文件
   * @param size {number} 单位Mb , 不传参表示任意大小文件
   * @param sizeObj {Object} 宽高尺寸 , {width:1 , height: 1}
   * @return: 无
   */
  validator: (file, typeArr, size, sizeObj) => {
    const testmsg = file.name.substring(file.name.lastIndexOf('.') + 1);
    let [extension, isLt] = [true, true];
    if (typeArr) {
      extension = typeArr.join(",").indexOf(testmsg) !== -1;
      if (!extension) {
        Vue.prototype.$message({
          message: `上传文件只能是 ${typeArr.join("/")} 格式!`,
          type: 'warning'
        });
        return false
      }
    }
    if (size && size>= 1) {
      isLt = file.size / 1024 / 1024 <= size;
      if (!isLt) {
        Vue.prototype.$message({
          message: `上传文件大小不能超过 ${size} M!`,
          type: 'warning'
        });
        return false
      }
    }
    if (size && size < 1) {
      const newSize = size * 1000
      isLt = file.size / 1024  <= newSize;
      if (!isLt) {
        Vue.prototype.$message({
          message: `上传文件大小不能超过 ${newSize} K!`,
          type: 'warning'
        });
        return false
      }
    }
    const fileReader = () => {
      return new Promise((resolve, reject) => {
        let reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = function (theFile) {
          resolve(theFile);
        }
      })
    }
    const imgReader = (theFile) => {
      return new Promise((resolve, reject) => {
        let img = new Image();
        img.src = theFile.srcElement.result;
        img.onload = function () {
          let { width, height } = img;
          if (width !== sizeObj.width || height !== sizeObj.height) {
            Vue.prototype.$message.error(`图片尺寸为 宽${width},高${height},不符合尺寸要求!`);
            // eslint-disable-next-line prefer-promise-reject-errors
            reject(false);
          } else {
            resolve(true);
          }
        }
      })
    }
    async function valdate() {
      if (sizeObj) {
        let theFile = await fileReader();
        let isSize = await imgReader(theFile);
        return isSize
      } else {
        return true
      }
    }
    return valdate();
  }
}

/**
 * @description:  根据用户类型( 未登录、用户登录、供应商登录) 判断是否需要登录
 * @param {Object} _this [vue组件的this]
 * @param {Number} type [可进行下步操作的用户类型]
 * @return:
 */
Vue.prototype.$isLogin = function (_this, type) {
  const { userType } = _this.$store.state.userInfo;
  const login = () => {
    _this.$router.push('/login/' + type);
  }
  return new Promise((resolve, reject) => {
    // 未登录的状态
    if (!userType) {
      reject();
      login();
      return;
    }
    // 登录状态和目标状态一致 进行后续业务逻辑
    if (userType === type) {
      resolve()
    } else {
      const name = type === 3 ? '供应商' : '买家';
      // 登录状态和目标状态不一致 提示后由用户选择是否跳转登录
      _this.$theConfirm({
        title: `此功能仅供${name}用户使用`,
        content: `您目前无法执行此操作,是否前往${name}用户登录页面`,
      }).then(() => {
        reject();
        login();
      })
    }
  })
}

/**
 * @description: 请求数据字段 设置options
 * @param {Object} _this [vue组件的this]
 * @param {String} codes [数据字典对应的code组成的字符串 例如 ,'code1,code2']
 * @return:
 */
Vue.prototype.$setOptions = function (_this, codes) {
  _this.$api.dictionary.childs(codes)
    .then((res) => {
      res.data.map((item) => {
        const element = item.details.map((subItem) => {
          return {
            id: subItem.value,
            label: subItem.text
          }
        })
        _this.$set(_this.options, item.code, element)
      })
    });
}
/**
 * @description: 判断ie的版本
 * @return:
 */
Vue.prototype.$IEVersion = function () {
  var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
  var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器
  var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
  var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
  if (isIE) {
    var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
    reIE.test(userAgent);
    var fIEVersion = parseFloat(RegExp["$1"]);
    if (fIEVersion == 7) {
      return 7;
    } else if (fIEVersion == 8) {
      return 8;
    } else if (fIEVersion == 9) {
      return 9;
    } else if (fIEVersion == 10) {
      return 10;
    } else {
      return 6;//IE版本<=7
    }
  } else if (isEdge) {
    return 'edge';//edge
  } else if (isIE11) {
    return 11; //IE11
  } else {
    return -1;//不是ie浏览器
  }
}

// 需要在asyncData中调用的方法通过这里注入上下文
export default (ctx, inject) => {
  // 注入上下文
  ctx.app.$clone = vm.$clone;
  ctx.app.$dataTransform = vm.$dataTransform;
  ctx.app.$parseUrl = vm.$parseUrl;
  ctx.app.$dataIsNull = vm.$dataIsNull;
}