text: /**
   * 基础函数
   */
  (function (window, $, undefined) {
  
      let serverUrl = window.location.origin + '/';
  
      /**
       * =============================================================================
       * **************************   基础函数类   **************************
       * =============================================================================
       */
      $.extend({
  
          /**
           * 身份识别码
           * @param text
           * @returns {*|string}
           */
          token: function (text) {
              let token = this.storage('token') || '';
              if (typeof text === 'string') {
                  this.storage('token', text);
                  token = text;
              }
              return token;
          },
  
          /**
           * 随机获取范围
           * @param Min
           * @param Max
           * @returns {*}
           */
          randNum(Min,Max){
              let Range = Max - Min;
              let Rand = Math.random();
              return Min + Math.round(Rand * Range); //四舍五入
          },
  
          /**
           * 获取数组最后一个值
           * @param array
           * @returns {boolean}
           */
          last: function (array) {
              let str = false;
              if (typeof array === 'object' && array.length > 0) {
                  str = array[array.length - 1];
              }
              return str;
          },
  
  
          /**
           * 字符串是否包含
           * @param string
           * @param find
           * @param lower
           * @returns {boolean}
           */
          strExists: function (string, find, lower = false) {
              string += "";
              find += "";
              if (lower !== true) {
                  string = string.toLowerCase();
                  find = find.toLowerCase();
              }
              return (string.indexOf(find) !== -1);
          },
  
          /**
           * 字符串是否左边包含
           * @param string
           * @param find
           * @param lower
           * @returns {boolean}
           */
          leftExists: function (string, find, lower = false) {
              string += "";
              find += "";
              if (lower !== true) {
                  string = string.toLowerCase();
                  find = find.toLowerCase();
              }
              return (string.substring(0, find.length) === find);
          },
  
          /**
           * 删除左边字符串
           * @param string
           * @param find
           * @param lower
           * @returns {string}
           */
          leftDelete: function (string, find, lower = false) {
              string += "";
              find += "";
              if (this.leftExists(string, find, lower)) {
                  string = string.substring(find.length)
              }
              return string ? string : '';
          },
  
          /**
           * 字符串是否右边包含
           * @param string
           * @param find
           * @param lower
           * @returns {boolean}
           */
          rightExists: function (string, find, lower = false) {
              string += "";
              find += "";
              if (lower !== true) {
                  string = string.toLowerCase();
                  find = find.toLowerCase();
              }
              return (string.substring(string.length - find.length) === find);
          },
  
          /**
           * 取字符串中间
           * @param string
           * @param start
           * @param end
           * @returns {*}
           */
          getMiddle: function (string, start, end) {
              string = string.toString();
              if (this.ishave(start) && this.strExists(string, start)) {
                  string = string.substring(string.indexOf(start) + start.length);
              }
              if (this.ishave(end) && this.strExists(string, end)) {
                  string = string.substring(0, string.indexOf(end));
              }
              return string;
          },
  
          /**
           * 截取字符串
           * @param string
           * @param start
           * @param end
           * @returns {string}
           */
          subString: function(string, start, end) {
              string += "";
              if (!this.ishave(end)) {
                  end = string.length;
              }
              return string.substring(start, end);
          },
  
          /**
           * 随机字符
           * @param len
           * @returns {string}
           */
          randomString: function (len) {
              len = len || 32;
              let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678oOLl9gqVvUuI1';
              let maxPos = $chars.length;
              let pwd = '';
              for (let i = 0; i < len; i++) {
                  pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
              }
              return pwd;
          },
  
          /**
           * 判断是否有
           * @param set
           * @returns {boolean}
           */
          ishave: function (set) {
              return !!(set !== null && set !== "null" && set !== undefined && set !== "undefined" && set);
          },
  
          /**
           * 相当于 intval
           * @param str
           * @param fixed
           * @returns {number}
           */
          runNum: function (str, fixed) {
              let _s = Number(str);
              if (_s + "" === "NaN") {
                  _s = 0;
              }
              if (/^[0-9]*[1-9][0-9]*$/.test(fixed)) {
                  _s = _s.toFixed(fixed);
                  let rs = _s.indexOf('.');
                  if (rs < 0) {
                      _s += ".";
                      for (let i = 0; i < fixed; i++) {
                          _s += "0";
                      }
                  }
              }
              return _s;
          },
  
          /**
           * 服务器地址
           * @param str
           * @returns {string}
           */
          serverUrl: function (str) {
              if (str.substring(0, 2) === "//" ||
                  str.substring(0, 7) === "http://" ||
                  str.substring(0, 8) === "https://" ||
                  str.substring(0, 6) === "ftp://" ||
                  str.substring(0, 1) === "/") {
                  return str;
              }
              return serverUrl + str;
          },
  
          /**
           * 获取IP地址详情
           * @param ip
           * @param callback
           */
          getIpInfo: function(ip, callback) {
              if (!this.strExists(ip, ".")) {
                  return;
              }
              let keyName = '__ip' + ip.substring(0, 1) + '__';
              let key = this.getMiddle(ip, '', '.');
              let res = this.loadFromlLocal(key, ip, '', keyName);
              if (typeof res == "object") {
                  if (typeof callback == "function") {
                      callback(res);
                  }
                  return;
              }
              $A.ajax({
                  url: $A.serverUrl('api/system/get/ipinfo'),
                  data: { ip: ip },
                  timeout: 8000,
                  success: (res) => {
                      this.savaToLocal(key, ip, res, keyName);
                      if (typeof callback == "function") {
                          callback(res);
                      }
                  }
              });
          },
  
          /**
           * 新增&&获取缓存数据
           * @param key
           * @param value
           * @returns {*}
           */
          storage: function(key, value) {
              let keyName = 'app';
              switch (window.location.pathname) {
                  case "/admin":
                      keyName+= ":" + window.location.pathname.substr(1);
                      break;
              }
              if (typeof value === 'undefined') {
                  return this.loadFromlLocal('__::', key, '', '__' + keyName + '__');
              }else{
                  this.savaToLocal('__::', key, value, '__' + keyName + '__');
              }
          },
  
          /**
           *  新增&&修改本地缓存
           *  @param {string} id 唯一id
           *  @param {string} key 标示
           *  @param value 新增&修改的值
           *  @param keyName 主键名称
           */
          savaToLocal: function(id, key, value, keyName) {
              try {
                  if (typeof keyName === 'undefined') keyName = '__seller__';
                  let seller = window.localStorage[keyName];
                  if (!seller) {
                      seller = {};
                      seller[id] = {};
                  } else {
                      seller = JSON.parse(seller);
                      if (!seller[id]) {
                          seller[id] = {};
                      }
                  }
                  seller[id][key] = value;
                  window.localStorage[keyName] = JSON.stringify(seller);
              } catch(e) { }
          },
  
          /**
           *  查询本地缓存
           *  @param {string} id 唯一id
           *  @param {string} key 标示
           *  @param def 如果查询不到显示的值
           *  @param keyName 主键名称
           */
          loadFromlLocal: function(id, key, def, keyName) {
              if (typeof keyName === 'undefined') keyName = '__seller__';
              let seller = window.localStorage[keyName];
              if (!seller) {
                  return def;
              }
              seller = JSON.parse(seller)[id];
              if (!seller) {
                  return def;
              }
              let ret = seller[key];
              return ret || def;
          },
  
          /**
           * 补零
           * @param str
           * @param length
           * @param after
           * @returns {*}
           */
          zeroFill: function(str, length, after) {
              str+= "";
              if (str.length >= length) {
                  return str;
              }
              let _str = '', _ret = '';
              for (let i = 0; i < length; i++) {
                  _str += '0';
              }
              if (after || typeof after === 'undefined') {
                  _ret = (_str + "" + str).substr(length * -1);
              } else {
                  _ret = (str + "" + _str).substr(0, length);
              }
              return _ret;
          },
  
          /**
           * 时间戳转时间格式
           * @param format
           * @param v
           * @returns {string}
           */
          formatDate: function(format, v) {
              if (format === '') {
                  format = 'Y-m-d H:i:s';
              }
              let dateObj;
              if (v instanceof Date) {
                  dateObj = v;
              }else {
                  if (typeof v === 'undefined') {
                      v = new Date().getTime();
                  }else if (/^(-)?\d{1,10}$/.test(v)) {
                      v = v * 1000;
                  } else if (/^(-)?\d{1,13}$/.test(v)) {
                      v = v * 1000;
                  } else if (/^(-)?\d{1,14}$/.test(v)) {
                      v = v * 100;
                  } else if (/^(-)?\d{1,15}$/.test(v)) {
                      v = v * 10;
                  } else if (/^(-)?\d{1,16}$/.test(v)) {
                      v = v * 1;
                  } else {
                      return v;
                  }
                  dateObj = new Date(v);
              }
              //
              format = format.replace(/Y/g, dateObj.getFullYear());
              format = format.replace(/m/g, this.zeroFill(dateObj.getMonth() + 1, 2));
              format = format.replace(/d/g, this.zeroFill(dateObj.getDate(), 2));
              format = format.replace(/H/g, this.zeroFill(dateObj.getHours(), 2));
              format = format.replace(/i/g, this.zeroFill(dateObj.getMinutes(), 2));
              format = format.replace(/s/g, this.zeroFill(dateObj.getSeconds(), 2));
              return format;
          },
  
          /**
           * 租用时间差(不够1个小时算一个小时)
           * @param s
           * @param e
           * @returns {*}
           */
          timeDiff: function(s, e) {
              if (typeof e === 'undefined') {
                  e = Math.round(new Date().getTime()/1000);
              }
              let d = e - s;
              if (d > 86400) {
                  let day = Math.floor(d / 86400);
                  let hour = Math.ceil((d - (day * 86400)) / 3600);
                  if (hour > 0) {
                      return day + '天' + hour + '小时';
                  } else {
                      return day + '天';
                  }
              } else if (d > 3600) {
                  return Math.ceil(d / 3600) + '小时';
              } else if (d > 60) {
                  return Math.ceil(d / 60) + '分钟';
              } else if (d > 10) {
                  return d + '秒';
              } else {
                  return '刚刚';
              }
          },
  
          /**
           * 检测手机号码格式
           * @param str
           * @returns {boolean}
           */
          isMobile: function(str) {
              return /^1([3456789])\d{9}$/.test(str);
          },
  
          /**
           * 是否手机号码
           * @param phone
           * @returns {boolean}
           */
          isPhone: function (phone) {
              return this.isMobile(phone);
          },
  
          /**
           * 根据两点间的经纬度计算距离
           * @param lng1
           * @param lat1
           * @param lng2
           * @param lat2
           * @returns {string|*}
           */
          getDistance: function (lng1, lat1, lng2, lat2) {
              let DEF_PI = 3.14159265359;         // PI
              let DEF_2PI = 6.28318530712;        // 2*PI
              let DEF_PI180 = 0.01745329252;      // PI/180.0
              let DEF_R = 6370693.5;              // radius of earth
              //
              let ew1, ns1, ew2, ns2;
              let dx, dy, dew;
              let distance;
              // 角度转换为弧度
              ew1 = lng1 * DEF_PI180;
              ns1 = lat1 * DEF_PI180;
              ew2 = lng2 * DEF_PI180;
              ns2 = lat2 * DEF_PI180;
              // 经度差
              dew = ew1 - ew2;
              // 若跨东经和西经180 度，进行调整
              if (dew > DEF_PI)
                  dew = DEF_2PI - dew;
              else if (dew < -DEF_PI)
                  dew = DEF_2PI + dew;
              dx = DEF_R * Math.cos(ns1) * dew; // 东西方向长度(在纬度圈上的投影长度)
              dy = DEF_R * (ns1 - ns2); // 南北方向长度(在经度圈上的投影长度)
              // 勾股定理求斜边长
              distance = Math.sqrt(dx * dx + dy * dy).toFixed(0);
              return distance;
          },
  
          /**
           * 设置网页标题
           * @param title
           */
          setTile(title) {
              document.title = title;
              let mobile = navigator.userAgent.toLowerCase();
              if (/iphone|ipad|ipod/.test(mobile)) {
                  let iframe = document.createElement('iframe');
                  iframe.style.display = 'none';
                  iframe.setAttribute('src', '/favicon.ico');
                  let iframeCallback = function () {
                      setTimeout(function () {
                          iframe.removeEventListener('load', iframeCallback);
                          document.body.removeChild(iframe)
                      }, 0)
                  };
                  iframe.addEventListener('load', iframeCallback);
                  document.body.appendChild(iframe)
              }
          },
  
          /**
           * 克隆对象
           * @param myObj
           * @returns {*}
           */
          cloneData(myObj) {
              if(typeof(myObj) !== 'object') return myObj;
              if(myObj === null) return myObj;
              //
              if (typeof myObj.length === 'number') {
                  let [ ...myNewObj ] = myObj;
                  return myNewObj;
              }else{
                  let { ...myNewObj } = myObj;
                  return myNewObj;
              }
          },
  
          /**
           * 将一个 JSON 字符串转换为对象（已try）
           * @param str
           * @param defaultVal
           * @returns {*}
           */
          jsonParse(str, defaultVal) {
              if (str === null) {
                  return defaultVal ? defaultVal : {};
              }
              if (typeof str === "object") {
                  return str;
              }
              try {
                  return JSON.parse(str);
              } catch (e) {
                  return defaultVal ? defaultVal : {};
              }
          },
  
          /**
           * 将 JavaScript 值转换为 JSON 字符串（已try）
           * @param json
           * @param defaultVal
           * @returns {string}
           */
          jsonStringify(json, defaultVal) {
              if (typeof json !== 'object') {
                  return json;
              }
              try{
                  return JSON.stringify(json);
              }catch (e) {
                  return defaultVal ? defaultVal : "";
              }
          },
  
          /**
           * 监听对象尺寸发生改变
           * @param obj
           * @param callback
           */
          resize(obj, callback) {
              let myObj = $A(obj);
              if (myObj.length === 0) return;
              let height = parseInt(myObj.outerHeight()),
                  width = parseInt(myObj.outerWidth());
              let inter = setInterval(()=>{
                  if (myObj.length === 0) clearInterval(inter);
                  let tmpHeight = parseInt(myObj.outerHeight()),
                      tmpWidth = parseInt(myObj.outerWidth());
                  if (height !== tmpHeight || width !== tmpWidth) {
                      height = tmpHeight;
                      width = tmpWidth;
                      console.log(width, height);
                      if (typeof callback === 'function') callback();
                  }
              }, 250);
          },
  
          /**
           * 是否IOS
           * @returns {boolean|string}
           */
          isIos() {
              let ua = typeof window !== 'undefined' && window.navigator.userAgent.toLowerCase();
              return ua && /iphone|ipad|ipod|ios/.test(ua);
          },
  
          /**
           * 是否安卓
           * @returns {boolean|string}
           */
          isAndroid() {
              let ua = typeof window !== 'undefined' && window.navigator.userAgent.toLowerCase();
              return ua && ua.indexOf('android') > 0;
          },
  
          /**
           * 是否微信
           * @returns {boolean}
           */
          isWeixin() {
              let ua = typeof window !== 'undefined' && window.navigator.userAgent.toLowerCase();
              return (ua.match(/MicroMessenger/i) + '' === 'micromessenger');
          },
  
          /**
           * 获取对象
           * @param obj
           * @param keys
           * @returns {string|*}
           */
          getObject(obj, keys) {
              let object = obj;
              if (this.count(obj) === 0 || this.count(keys) === 0) {
                  return "";
              }
              let arr = keys.replace(/,/g, "|").replace(/\./g, "|").split("|");
              $A.each(arr, (index, key) => {
                  object = typeof object[key] === "undefined" ? "" : object[key];
              });
              return object;
          },
  
          /**
           * 统计数组或对象长度
           * @param obj
           * @returns {number}
           */
          count(obj) {
              try {
                  if (typeof obj === "undefined") {
                      return 0;
                  }
                  if (typeof obj === "number") {
                      obj+= "";
                  }
                  if (typeof obj.length === 'number') {
                      return obj.length;
                  } else {
                      let i = 0, key;
                      for (key in obj) {
                          i++;
                      }
                      return i;
                  }
              }catch (e) {
                  return 0;
              }
          },
  
          /**
           * 将数组或对象内容部分拼成字符串
           * @param obj
           * @returns {string}
           */
          objImplode(obj) {
              if (obj === null) {
                  return "";
              }
              let str = "";
              $A.each(obj, (key, val) => {
                  if (val !== null) {
                      if (typeof val === "object" && this.count(val) > 0) {
                          str += this.objImplode(val);
                      } else {
                          str += String(val);
                      }
                  }
              });
              return str.replace(/\s/g, "").replace(/undefined/g, "");
          },
  
          /**
           * 指定键获取url参数
           * @param key
           * @returns {*}
           */
          urlParameter(key) {
              let params = this.urlParameterAll();
              return typeof key === "undefined" ? params : params[key];
          },
  
          urlParameterAll() {
              let search = window.location.search || "";
              let arr = [];
              if (this.strExists(search, "?")) {
                  arr = this.getMiddle(search, "?").split("&");
              }
              let params = {};
              for (let i = 0; i < arr.length; i++) {
                  let data = arr[i].split("=");
                  if (data.length === 2) {
                      params[data[0]] = data[1];
                  }
              }
              return params;
          },
  
          /**
           * 删除地址中的参数
           * @param url
           * @param parameter
           * @returns {string|*}
           */
          removeURLParameter(url, parameter) {
              if (parameter instanceof Array) {
                  parameter.forEach((key) => {
                      url = $A.removeURLParameter(url, key)
                  });
                  return url;
              }
              var urlparts = url.split('?');
              if (urlparts.length >= 2) {
                  //参数名前缀
                  var prefix = encodeURIComponent(parameter) + '=';
                  var pars = urlparts[1].split(/[&;]/g);
  
                  //循环查找匹配参数
                  for (var i = pars.length; i-- > 0;) {
                      if (pars[i].lastIndexOf(prefix, 0) !== -1) {
                          //存在则删除
                          pars.splice(i, 1);
                      }
                  }
  
                  return urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : '');
              }
              return url;
          },
  
          /**
           * 连接加上参数
           * @param url
           * @param params
           * @returns {*}
           */
          urlAddParams(url, params) {
              if (typeof params === "object" && params !== null) {
                  url+= "";
                  url+= url.indexOf("?") === -1 ? '?' : '';
                  for (var key in params) {
                      if (!params.hasOwnProperty(key)) {
                          continue;
                      }
                      url+= '&' + key + '=' + params[key];
                  }
              }
              return url.replace("?&", "?");
          },
  
          /**
           * 链接字符串
           * @param value 第一个参数为连接符
           * @returns {string}
           */
          stringConnect(...value) {
              let s = null;
              let text = "";
              value.forEach((val) => {
                  if (s === null) {
                      s = val;
                  }else if (val){
                      if (val && text) text+= s;
                      text+= val;
                  }
              });
              return text;
          },
  
          /**
           * 判断两个对象是否相等
           * @param x
           * @param y
           * @returns {boolean}
           */
          objEquals(x, y) {
              let f1 = x instanceof Object;
              let f2 = y instanceof Object;
              if (!f1 || !f2) {
                  return x === y
              }
              if (Object.keys(x).length !== Object.keys(y).length) {
                  return false
              }
              for (let p in x) {
                  if (x.hasOwnProperty(p)) {
                      let a = x[p] instanceof Object;
                      let b = y[p] instanceof Object;
                      if (a && b) {
                          if (!this.objEquals(x[p], y[p])) {
                              return false;
                          }
                      } else if (x[p] != y[p]) {
                          return false;
                      }
                  }
              }
              return true;
          },
  
          /**
           * 输入框内插入文本
           * @param object
           * @param content
           */
          insert2Input (object, content) {
              if (object === null || typeof object !== "object") return;
              if (typeof object.length === 'number' && object.length > 0) object = object[0];
  
              let ele = typeof object.$el === "object" ? $A(object.$el) : $A(object);
              if (ele.length === 0) return;
              let eleDom = ele[0];
  
              if (eleDom.tagName != "INPUT" && eleDom.tagName != "TEXTAREA") {
                  if (ele.find("input").length === 0) {
                      ele = ele.find("textarea");
                  }else{
                      ele = ele.find("input");
                  }
              }
              if (ele.length === 0) return;
              eleDom = ele[0];
  
              if (eleDom.tagName != "INPUT" && eleDom.tagName != "TEXTAREA") return;
  
              let text = ele.val();
              let { selectionStart, selectionEnd } = eleDom;
  
              ele.val(`${text.substring(0, selectionStart)}${content}${text.substring(selectionEnd, text.length)}`);
              eleDom.dispatchEvent(new Event('input'));
  
              setTimeout(() => {
                  if (eleDom.setSelectionRange) {
                      let pos = text.substring(0, selectionStart).length + content.length;
                      eleDom.focus();
                      eleDom.setSelectionRange(pos, pos);
                  }
              }, 10);
          },
  
          /**
           * iOS上虚拟键盘引起的触控错位
           */
          iOSKeyboardFixer() {
              if (!this.isIos()) {
                  return;
              }
              document.body.scrollTop = document.body.scrollTop + 1;
              document.body.scrollTop = document.body.scrollTop - 1;
          },
  
          autoDevwid(width) {
              let _width = width || 640;
              new function () {
                  let _self = this;
                  _self.width = _width;           //设置默认最大宽度
                  _self.fontSize = 30;            //默认字体大小
                  _self.widthProportion = function () {
                      let p = (document.body && document.body.clientWidth || document.getElementsByTagName("html")[0].offsetWidth) / _self.width;
                      return p > 1 ? 1 : p < 0.38 ? 0.38 : p;
                  };
                  _self.changePage = function () {
                      document.getElementsByTagName("html")[0].setAttribute("style", "font-size:" + _self.widthProportion() * _self.fontSize + "px !important");
                  };
                  _self.changePage();
                  window.addEventListener('resize', function () {
                      _self.changePage();
                  }, false);
              };
              //
              let scale = $A(window).width() / _width;
              $A(".__auto").each(function () {
                  if ($A(this).attr("data-original") !== "1") {
                      $A(this).attr("data-original-top", parseInt($A(this).css("top")));
                      $A(this).attr("data-original-right", parseInt($A(this).css("right")));
                      $A(this).attr("data-original-bottom", parseInt($A(this).css("bottom")));
                      $A(this).attr("data-original-left", parseInt($A(this).css("left")));
                      $A(this).attr("data-original-width", parseInt($A(this).css("width")));
                      $A(this).attr("data-original-height", parseInt($A(this).css("height")));
                      $A(this).attr("data-original-line-height", parseInt($A(this).css("line-height")));
                      $A(this).attr("data-original", "1");
                  }
                  let _t = parseInt($A(this).attr("data-original-top"));
                  let _r = parseInt($A(this).attr("data-original-right"));
                  let _b = parseInt($A(this).attr("data-original-bottom"));
                  let _l = parseInt($A(this).attr("data-original-left"));
                  let _w = parseInt($A(this).attr("data-original-width"));
                  let _h = parseInt($A(this).attr("data-original-height"));
                  let _lh = parseInt($A(this).attr("data-original-line-height"));
                  //
                  let _css = {};
                  if (_t > 0) _css['top'] = _t * scale;
                  if (_r > 0) _css['right'] = _r * scale;
                  if (_b > 0) _css['bottom'] = _b * scale;
                  if (_l > 0) _css['left'] = _l * scale;
                  if (_w > 0) _css['width'] = _w * scale;
                  if (_h > 0) _css['height'] = _h * scale;
                  if (_lh > 0) _css['line-height'] = (_lh * scale) + 'px';
                  $A(this).css(_css);
              });
              return scale;
          }
  
      });
  
      /**
       * =============================================================================
       * ****************************   ihttp   ****************************
       * =============================================================================
       */
      $.extend({
  
          serializeObject (obj, parents) {
              if (typeof obj === 'string') return obj;
              let resultArray = [];
              let separator = '&';
              parents = parents || [];
              let newParents;
  
              function var_name(name) {
                  if (parents.length > 0) {
                      let _parents = '';
                      for (let j = 0; j < parents.length; j++) {
                          if (j === 0) _parents += parents[j];
                          else _parents += '[' + encodeURIComponent(parents[j]) + ']';
                      }
                      return _parents + '[' + encodeURIComponent(name) + ']';
                  }
                  else {
                      return encodeURIComponent(name);
                  }
              }
  
              function var_value(value) {
                  return encodeURIComponent(value);
              }
  
              for (let prop in obj) {
                  if (obj.hasOwnProperty(prop)) {
                      let toPush;
                      if (Array.isArray(obj[prop])) {
                          toPush = [];
                          for (let i = 0; i < obj[prop].length; i++) {
                              if (!Array.isArray(obj[prop][i]) && typeof obj[prop][i] === 'object') {
                                  newParents = parents.slice();
                                  newParents.push(prop);
                                  newParents.push(i + '');
                                  toPush.push($.serializeObject(obj[prop][i], newParents));
                              }
                              else {
                                  toPush.push(var_name(prop) + '[]=' + var_value(obj[prop][i]));
                              }
  
                          }
                          if (toPush.length > 0) resultArray.push(toPush.join(separator));
                      }
                      else if (obj[prop] === null) {
                          resultArray.push(var_name(prop) + '=');
                      }
                      else if (typeof obj[prop] === 'object') {
                          // Object, convert to named array
                          newParents = parents.slice();
                          newParents.push(prop);
                          toPush = $.serializeObject(obj[prop], newParents);
                          if (toPush !== '') resultArray.push(toPush);
                      }
                      else if (typeof obj[prop] !== 'undefined' && obj[prop] !== '') {
                          // Should be string or plain value
                          resultArray.push(var_name(prop) + '=' + var_value(obj[prop]));
                      }
                      else if (obj[prop] === '') resultArray.push(var_name(prop));
                  }
              }
              return resultArray.join(separator);
          },
  
          // Global Ajax Setup
          globalAjaxOptions: {},
          ajaxSetup (options) {
              if (options.type) options.method = options.type;
              $.each(options, function (optionName, optionValue) {
                  $.globalAjaxOptions[optionName] = optionValue;
              });
          },
  
          // Ajax
          _jsonpRequests: 0,
          ihttp(options) {
              let defaults = {
                  method: 'GET',
                  data: false,
                  async: true,
                  cache: true,
                  user: '',
                  password: '',
                  headers: {},
                  xhrFields: {},
                  statusCode: {},
                  processData: true,
                  dataType: 'text',
                  contentType: 'application/x-www-form-urlencoded',
                  timeout: 0
              };
              let callbacks = ['beforeSend', 'error', 'complete', 'success', 'statusCode'];
  
  
              //For jQuery guys
              if (options.type) options.method = options.type;
  
              // Merge global and defaults
              $.each($.globalAjaxOptions, function (globalOptionName, globalOptionValue) {
                  if (callbacks.indexOf(globalOptionName) < 0) defaults[globalOptionName] = globalOptionValue;
              });
  
              // Function to run XHR callbacks and events
              function fireAjaxCallback(eventName, eventData, callbackName) {
                  let a = arguments;
                  if (eventName) $(document).trigger(eventName, eventData);
                  if (callbackName) {
                      // Global callback
                      if (callbackName in $.globalAjaxOptions) $.globalAjaxOptions[callbackName](a[3], a[4], a[5], a[6]);
                      // Options callback
                      if (options[callbackName]) options[callbackName](a[3], a[4], a[5], a[6]);
                  }
              }
  
              // Merge options and defaults
              $.each(defaults, function (prop, defaultValue) {
                  if (!(prop in options)) options[prop] = defaultValue;
              });
  
              // Default URL
              if (!options.url) {
                  options.url = window.location.toString();
              }
              // Parameters Prefix
              let paramsPrefix = options.url.indexOf('?') >= 0 ? '&' : '?';
  
              // UC method
              let _method = options.method.toUpperCase();
              // Data to modify GET URL
              if ((_method === 'GET' || _method === 'HEAD' || _method === 'OPTIONS' || _method === 'DELETE') && options.data) {
                  let stringData;
                  if (typeof options.data === 'string') {
                      // Should be key=value string
                      if (options.data.indexOf('?') >= 0) stringData = options.data.split('?')[1];
                      else stringData = options.data;
                  }
                  else {
                      // Should be key=value object
                      stringData = $.serializeObject(options.data);
                  }
                  if (stringData.length) {
                      options.url += paramsPrefix + stringData;
                      if (paramsPrefix === '?') paramsPrefix = '&';
                  }
              }
              // JSONP
              if (options.dataType === 'json' && options.url.indexOf('callback=') >= 0) {
  
                  let callbackName = 'f7jsonp_' + Date.now() + ($._jsonpRequests++);
                  let abortTimeout;
                  let callbackSplit = options.url.split('callback=');
                  let requestUrl = callbackSplit[0] + 'callback=' + callbackName;
                  if (callbackSplit[1].indexOf('&') >= 0) {
                      let addVars = callbackSplit[1].split('&').filter(function (el) {
                          return el.indexOf('=') > 0;
                      }).join('&');
                      if (addVars.length > 0) requestUrl += '&' + addVars;
                  }
  
                  // Create script
                  let script = document.createElement('script');
                  script.type = 'text/javascript';
                  script.onerror = function () {
                      clearTimeout(abortTimeout);
                      fireAjaxCallback(undefined, undefined, 'error', null, 'scripterror');
                      fireAjaxCallback('ajaxComplete ajax:complete', {scripterror: true}, 'complete', null, 'scripterror');
                  };
                  script.src = requestUrl;
  
                  // Handler
                  window[callbackName] = function (data) {
                      clearTimeout(abortTimeout);
                      fireAjaxCallback(undefined, undefined, 'success', data);
                      script.parentNode.removeChild(script);
                      script = null;
                      delete window[callbackName];
                  };
                  document.querySelector('head').appendChild(script);
  
                  if (options.timeout > 0) {
                      abortTimeout = setTimeout(function () {
                          script.parentNode.removeChild(script);
                          script = null;
                          fireAjaxCallback(undefined, undefined, 'error', null, 'timeout');
                      }, options.timeout);
                  }
  
                  return;
              }
  
              // Cache for GET/HEAD requests
              if (_method === 'GET' || _method === 'HEAD' || _method === 'OPTIONS' || _method === 'DELETE') {
                  if (options.cache === false) {
                      options.url += (paramsPrefix + '_nocache=' + Date.now());
                  }
              }
  
              // Create XHR
              let xhr = new XMLHttpRequest();
  
              // Save Request URL
              xhr.requestUrl = options.url;
              xhr.requestParameters = options;
  
              // Open XHR
              xhr.open(_method, options.url, options.async, options.user, options.password);
  
              // Create POST Data
              let postData = null;
  
              if ((_method === 'POST' || _method === 'PUT' || _method === 'PATCH') && options.data) {
                  if (options.processData) {
                      let postDataInstances = [ArrayBuffer, Blob, Document, FormData];
                      // Post Data
                      if (postDataInstances.indexOf(options.data.constructor) >= 0) {
                          postData = options.data;
                      }
                      else {
                          // POST Headers
                          let boundary = '---------------------------' + Date.now().toString(16);
  
                          if (options.contentType === 'multipart\/form-data') {
                              xhr.setRequestHeader('Content-Type', 'multipart\/form-data; boundary=' + boundary);
                          }
                          else {
                              xhr.setRequestHeader('Content-Type', options.contentType);
                          }
                          postData = '';
                          let _data = $.serializeObject(options.data);
                          if (options.contentType === 'multipart\/form-data') {
                              boundary = '---------------------------' + Date.now().toString(16);
                              _data = _data.split('&');
                              let _newData = [];
                              for (let i = 0; i < _data.length; i++) {
                                  _newData.push('Content-Disposition: form-data; name="' + _data[i].split('=')[0] + '"\r\n\r\n' + _data[i].split('=')[1] + '\r\n');
                              }
                              postData = '--' + boundary + '\r\n' + _newData.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n';
                          }
                          else {
                              postData = _data;
                          }
                      }
                  }
                  else {
                      postData = options.data;
                  }
  
              }
  
              // Additional headers
              if (options.headers) {
                  $.each(options.headers, function (headerName, headerCallback) {
                      xhr.setRequestHeader(headerName, headerCallback);
                  });
              }
  
              // Check for crossDomain
              if (typeof options.crossDomain === 'undefined') {
                  options.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(options.url) && RegExp.$2 !== window.location.host;
              }
  
              if (!options.crossDomain) {
                  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
              }
  
              if (options.xhrFields) {
                  $.each(options.xhrFields, function (fieldName, fieldValue) {
                      xhr[fieldName] = fieldValue;
                  });
              }
  
              let xhrTimeout;
              // Handle XHR
              xhr.onload = function (e) {
                  if (xhrTimeout) clearTimeout(xhrTimeout);
                  if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) {
                      let responseData;
                      if (options.dataType === 'json') {
                          try {
                              responseData = JSON.parse(xhr.responseText);
                              fireAjaxCallback('ajaxSuccess ajax:success', {xhr: xhr}, 'success', responseData, xhr.status, xhr);
                          }
                          catch (err) {
                              fireAjaxCallback('ajaxError ajax:error', {
                                  xhr: xhr,
                                  parseerror: true
                              }, 'error', xhr, 'parseerror');
                          }
                      }
                      else {
                          responseData = xhr.responseType === 'text' || xhr.responseType === '' ? xhr.responseText : xhr.response;
                          fireAjaxCallback('ajaxSuccess ajax:success', {xhr: xhr}, 'success', responseData, xhr.status, xhr);
                      }
                  }
                  else {
                      fireAjaxCallback('ajaxError ajax:error', {xhr: xhr}, 'error', xhr, xhr.status);
                  }
                  if (options.statusCode) {
                      if ($.globalAjaxOptions.statusCode && $.globalAjaxOptions.statusCode[xhr.status]) $.globalAjaxOptions.statusCode[xhr.status](xhr);
                      if (options.statusCode[xhr.status]) options.statusCode[xhr.status](xhr);
                  }
                  fireAjaxCallback('ajaxComplete ajax:complete', {xhr: xhr}, 'complete', xhr, xhr.status);
              };
  
              xhr.onerror = function (e) {
                  if (xhrTimeout) clearTimeout(xhrTimeout);
                  fireAjaxCallback('ajaxError ajax:error', {xhr: xhr}, 'error', xhr, xhr.status);
                  fireAjaxCallback('ajaxComplete ajax:complete', {xhr: xhr, error: true}, 'complete', xhr, 'error');
              };
  
              // Ajax start callback
              fireAjaxCallback('ajaxStart ajax:start', {xhr: xhr}, 'start', xhr);
              fireAjaxCallback(undefined, undefined, 'beforeSend', xhr);
  
              // Timeout
              if (options.timeout > 0) {
                  xhr.onabort = function () {
                      if (xhrTimeout) clearTimeout(xhrTimeout);
                  };
                  xhrTimeout = setTimeout(function () {
                      xhr.abort();
                      fireAjaxCallback('ajaxError ajax:error', {xhr: xhr, timeout: true}, 'error', xhr, 'timeout');
                      fireAjaxCallback('ajaxComplete ajax:complete', {
                          xhr: xhr,
                          timeout: true
                      }, 'complete', xhr, 'timeout');
                  }, options.timeout);
              }
  
              // Send XHR
              xhr.send(postData);
  
              // Return XHR object
              return xhr;
          }
      });
  
      /**
       * =============================================================================
       * *************************   Bootstrap extend   ************************
       * =============================================================================
       */
      $.extend({
  
          toast(params, timeout, template) {
              let _bg = function(num) {
                  let container = $A(".__bootstrap_toast_container");
                  if (container.length > 0) {
                      let bgobj = container.find(".alert-bg");
                      let bgnum = parseInt(bgobj.attr("data-num"));
                      bgnum+= num;
                      bgobj.attr("data-num", bgnum);
                      if (bgnum > 0) {
                          bgobj.show();
                      }else{
                          bgobj.hide();
                      }
                  }
              };
              if (!params) return false;
              if (typeof params === 'object' && params.length > 0) {
                  if (params.attr("data-show-bg") === "true") _bg(-1);
                  params.css({width: Math.ceil(params.outerWidth())});
                  params.addClass("leave");
                  setTimeout(()=>{ params.remove() }, 300);
                  return;
              }
              if (typeof timeout === 'string') {
                  template = timeout;
                  timeout = 2500;
              }
              if (typeof params === 'string') params = { title: params };
              if (typeof params.timeout === 'undefined') params.timeout = 2500;
              if (typeof params.template === 'undefined') params.template = 'success';
              if (typeof params.fixed === 'undefined') params.fixed = false;
              if (typeof params.close === 'undefined') params.close = true;
              if (typeof timeout !== 'undefined') params.timeout = timeout;
              if (typeof template !== 'undefined') params.template = template;
              //
              let container = $A(".__bootstrap_toast_container");
              if (container.length === 0) {
                  $A("<style>")
                      .attr({type: "text/css"})
                      .html(
                          ".__bootstrap_toast_container{position:fixed;z-index:99999;top:5%;right:5%;padding:0;text-align:right;}" +
                          ".__bootstrap_toast_container .alert-bg{position:fixed;display:none;z-index:1;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,0.6);}" +
                          ".__bootstrap_toast_container .alert-body{position:relative;z-index:2;display:block;min-width:180px;text-align:left;opacity:0;transform:translate3d(0,100px,0);-webkit-transform:translate3d(0,100px,0);transition-duration:300ms;-webkit-transition-duration:300ms;}" +
                          ".__bootstrap_toast_container .alert-body.enter{opacity:1;transform:translate3d(0,0,0);-webkit-transform:translate3d(0,0,0);}" +
                          ".__bootstrap_toast_container .alert-body.leave{position:absolute;top:0;right:0;z-index:3;opacity:0;transform:translate3d(100%,0,0);-webkit-transform:translate3d(100%,0,0);transition-duration:200ms;-webkit-transition-duration:300ms;}" +
                          "")
                      .appendTo("head");
                  $A("body").append("<div class='__bootstrap_toast_container'><div class='alert-bg' data-num='0'></div></div>");
                  container = $A(".__bootstrap_toast_container");
              }
              //
              let $intemp = $A('<div class="alert-body alert alert-' + params.template + ' alert-dismissible" role="alert"><button type="button" class="close"><span aria-hidden="true">&times;</span></button>' + params.title + '</div>');
              if (params.close === false) {
                  $intemp.removeClass("alert-dismissible");
                  $intemp.find(".close").remove();
              }else{
                  $intemp.find(".close").click(()=>{ $A.toast($intemp); });
              }
              if (params.fixed === true) {
                  _bg(1);
                  $intemp.attr("data-show-bg", "true");
              }
              container.append($intemp);
              //
              if (typeof params.timeout === 'number') {
                  setTimeout(()=>{ $A.toast($intemp) }, params.timeout)
              }
              setTimeout(()=>{ $intemp.addClass("enter") }, 10);
              //
              return $intemp;
          }
      });
  
      /**
       * =============================================================================
       * *****************************   ajax   ****************************
       * =============================================================================
       */
      $.extend({
  
          ajax(params) {
              if (!params) return false;
              if (typeof params.url === 'undefined') return false;
              if (typeof params.data === 'undefined') params.data = {};
              if (typeof params.cache === 'undefined') params.cache = false;
              if (typeof params.method === 'undefined') params.method = 'GET';
              if (typeof params.timeout === 'undefined') params.timeout = 30000;
              if (typeof params.dataType === 'undefined') params.dataType = 'json';
              if (typeof params.beforeSend === 'undefined') params.beforeSend = () => { };
              if (typeof params.complete === 'undefined') params.complete = () => { };
              if (typeof params.afterComplete === 'undefined') params.afterComplete = () => { };
              if (typeof params.success === 'undefined') params.success = () => { };
              if (typeof params.error === 'undefined') params.error = () => { };
              //
              let loadText = "数据加载中.....";
              let busyNetwork = "网络繁忙，请稍后再试！";
              if (typeof $A.app === 'object' && typeof $A.app.$L === 'function') {
                  loadText = $A.app.$L(loadText);
                  busyNetwork = $A.app.$L(busyNetwork);
              }
              //
              let toastID = null, beforeTitle = '', errorTitle = '';
              if (typeof $A.app === 'object' && typeof $A.app.$Message === 'object') {
                  if (typeof params.beforeSend === 'string')  {
                      beforeTitle = params.beforeSend;
                      params.beforeSend = () => { toastID = $A.app.$Message.loading({content:beforeTitle, duration: 0}); };
                  }else if (params.beforeSend === true) {
                      params.beforeSend = () => { toastID = $A.app.$Message.loading({content:loadText, duration: 0}); };
                  }
                  if (typeof params.error === 'string')  {
                      errorTitle = params.error;
                      params.error = () => { $A.app.$Message.error({content:errorTitle, duration: 5}); };
                  }else if (params.error === true) {
                      params.error = () => { $A.app.$Message.error({content:busyNetwork, duration: 5}); };
                  }
                  if (params.complete === true) {
                      params.complete = () => { toastID?toastID():'' };
                  }
              }else{
                  if (typeof params.beforeSend === 'string')  {
                      beforeTitle = params.beforeSend;
                      params.beforeSend = () => { toastID = $A.toast({title:beforeTitle, fixed: true, timeout: false}); };
                  }else if (params.beforeSend === true) {
                      params.beforeSend = () => { toastID = $A.toast({title:loadText, fixed: true, timeout: false}); };
                  }
                  if (typeof params.error === 'string')  {
                      errorTitle = params.error;
                      params.error = () => { $A.toast(errorTitle, "danger"); };
                  }else if (params.error === true) {
                      params.error = () => { $A.toast(busyNetwork, "danger"); };
                  }
                  if (params.complete === true) {
                      params.complete = () => { toastID?$A.toast(toastID):'' };
                  }
              }
              //
              if (typeof params.header !== 'object') params.header = {};
              params.header['Content-Type'] = 'application/json';
              params.header['language'] = window.localStorage['__language:type__'] || 'zh';
              params.header['token'] = $A.token();
              //
              params.data['__Access-Control-Allow-Origin'] = true;
              params.beforeSend();
              $A.ihttp({
                  url: params.url,
                  data: params.data,
                  cache: params.cache,
                  headers: params.header,
                  method: params.method.toUpperCase(),
                  contentType: "OPTIONS",
                  crossDomain: true,
                  dataType: params.dataType,
                  timeout: params.timeout,
                  success: function(data, status, xhr) {
                      params.complete();
                      params.success(data, status, xhr);
                      params.afterComplete(true);
                  },
                  error: function(xhr, status) {
                      params.complete();
                      params.error(xhr, status);
                      params.afterComplete(false);
                  }
              });
          }
      });
  
  
      /**
       * =============================================================================
       * *****************************   manage assist   ****************************
       * =============================================================================
       */
      $.extend({
  
          /**
           *  对象中有Date格式的转成指定格式
           * @param myObj
           * @param format  默认格式：Y-m-d
           * @returns {*}
           */
          date2string(myObj, format) {
              if (myObj === null) {
                  return myObj;
              }
              if (typeof format === "undefined") {
                  format = "Y-m-d";
              }
              if (typeof myObj === "object") {
                  if (myObj instanceof Date) {
                      return $A.formatDate(format, myObj);
                  }
                  $A.each(myObj, (key, val)=>{
                      myObj[key] = $A.date2string(val, format);
                  });
                  return myObj;
              }
              return myObj;
          },
  
          /**
           * 获取一些指定时间
           * @param str
           * @param retInt
           * @returns {*|string}
           */
          getData(str, retInt = false) {
              let now = new Date();                   //当前日期
              let nowDayOfWeek = now.getDay();        //今天本周的第几天
              let nowDay = now.getDate();             //当前日
              let nowMonth = now.getMonth();          //当前月
              let nowYear = now.getYear();            //当前年
              nowYear += (nowYear < 2000) ? 1900 : 0;
              let lastMonthDate = new Date();         //上月日期
              lastMonthDate.setDate(1);
              lastMonthDate.setMonth(lastMonthDate.getMonth()-1);
              let lastMonth = lastMonthDate.getMonth();
              let getQuarterStartMonth = () => {
                  let quarterStartMonth = 0;
                  if(nowMonth < 3) {
                      quarterStartMonth = 0;
                  }
                  if (2 < nowMonth && nowMonth < 6) {
                      quarterStartMonth = 3;
                  }
                  if (5 < nowMonth && nowMonth < 9) {
                      quarterStartMonth = 6;
                  }
                  if (nowMonth > 8) {
                      quarterStartMonth = 9;
                  }
                  return quarterStartMonth;
              };
              let getMonthDays = (myMonth) => {
                  let monthStartDate = new Date(nowYear, myMonth, 1);
                  let monthEndDate = new Date(nowYear, myMonth + 1, 1);
                  return (monthEndDate - monthStartDate)/(1000 * 60 * 60 * 24);
              };
              //
              let time = now.getTime();
              switch (str) {
                  case '今天':
                      time = now;
                      break;
                  case '昨天':
                      time = now - 86400000;
                      break;
                  case '前天':
                      time = now - 86400000 * 2;
                      break;
                  case '本周':
                      time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek);
                      break;
                  case '本周结束':
                      time = new Date(nowYear, nowMonth, nowDay + (6 - nowDayOfWeek));
                      break;
                  case '上周':
                      time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek - 7);
                      break;
                  case '上周结束':
                      time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek - 1);
                      break;
                  case '本周2':
                      time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek + 1);
                      break;
                  case '本周结束2':
                      time = new Date(nowYear, nowMonth, nowDay + (6 - nowDayOfWeek) + 1);
                      break;
                  case '上周2':
                      time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek - 7 + 1);
                      break;
                  case '上周结束2':
                      time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek - 1 + 1);
                      break;
                  case '本月':
                      time = new Date(nowYear, nowMonth, 1);
                      break;
                  case '本月结束':
                      time = new Date(nowYear, nowMonth, getMonthDays(nowMonth));
                      break;
                  case '上个月':
                      time = new Date(nowYear, lastMonth, 1);
                      break;
                  case '上个月结束':
                      time = new Date(nowYear, lastMonth, getMonthDays(lastMonth));
                      break;
                  case '本季度':
                      time = new Date(nowYear, getQuarterStartMonth(), 1);
                      break;
                  case '本季度结束':
                      let quarterEndMonth = getQuarterStartMonth() + 2;
                      time = new Date(nowYear, quarterEndMonth, getMonthDays(quarterEndMonth));
                      break;
              }
              if (retInt === true) {
                  return time;
              }
              return $A.formatDate("Y-m-d", parseInt(time / 1000))
          },
  
          /**
           * 字节转换
           * @param bytes
           * @returns {string}
           */
          bytesToSize(bytes) {
              if (bytes === 0) return '0 B';
              let k = 1024;
              let sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
              let i = Math.floor(Math.log(bytes) / Math.log(k));
              if (typeof sizes[i] === "undefined") {
                  return '0 B';
              }
              return $A.runNum((bytes / Math.pow(k, i)), 2) + ' ' + sizes[i];
          }
      });
  
      window.$A = $;
  })(window, window.jQuery);
  