/**version-1.0*/
let install = {};

import request from "./request";
import * as lodash from "lodash";
import { Loading, Message, MessageBox, Notification, Form } from "element-ui";
import store from "../store";
import ElImageViewer from "../components/VabUpload/image-viewer";

import { getToken } from "./auth";
import XEUtils from "xe-utils";

import prefixConfig from "@/prefixConfig.js";
import moment from "moment";

let imFun = {
  request,
  lodash,
  Loading,
  Message,
  MessageBox,
  Notification,
  Form,
  store,
  getToken,
  prefixConfig,
};

function reqImg(a) {
  return require("@/resources/images/" + a);
}

const FILE_ICON_NAME_MAP = {
  word: "ico-wrod.svg",
  excel: "ico-excel.svg",
  ppt: "ico-ppt.svg",
  pdf: "ico-pdf.svg",
  picture: "ico-photo.svg",
  video: "ico-video.svg",
  audio: "ico-music.svg",
  html: "ico-html.svg",
  txt: "ico-txt.svg",
  java: "ico-java.svg",
  vue: "ico-vue.svg",
  xml: "ico-xml.svg",
  flash: "ico-flash.svg",
  zip: "ico-yasuobao.svg",
  exe: "ico-ext.svg",
  psd: "ico-psd.svg",
  folder: "ico-wenjianjia.svg",
  other: "ico-default_wenjian.svg",
};

const FILE_ICON_TYPE_MAP = {
  doc: "word",
  docx: "word",
  xls: "excel",
  xlsx: "excel",
  ppt: "ppt",
  pptx: "ppt",
  pdf: "pdf",
  jpg: "picture",
  jpeg: "picture",
  png: "picture",
  gif: "picture",
  mp3: "video",
  mp4: "video",
  mpg: "video",
  mkv: "video",
  rmvb: "video",
  avi: "video",
  mov: "video",
  wav: "audio",
  html: "html",
  htm: "html",
  txt: "txt",
  java: "java",
  vue: "vue",
  xml: "xml",
  swf: "flash",
  zip: "zip",
  rar: "zip",
  "7z": "zip",
  // exe: 'exe',
  psd: "psd",
};

const accessToken = imFun.store.getters["user/token"];

const loadingText = "";
const messageDuration = 3000;

install = (Vue, opts = {}) => {
  /**http请求*/
  let $http = async function (option) {
    option = option || {};
    if (!option.loadingTarget && this.$el) {
      option.loadingTarget = this.$el;
    }
    if (!option.vueTarget) {
      option.vueTarget = this;
    }
    if (option.sync === false) {
      return await imFun.request(option);
    } else {
      return imFun.request(option);
    }
  };

  Vue.prototype.$commonHttp = function (opts) {
    let defaultOption = {
      addCreateInfo: true,
      queryCreateInfo: window.$vueRoot.$store.getters.queryCreateInfo || "0",
    };
    let option = Object.assign({}, defaultOption, opts);
    if (opts.addCreateInfo === null || opts.addCreateInfo === undefined) {
      option.addCreateInfo = defaultOption.addCreateInfo;
    }
    if (
      opts.queryCreateInfo === null
      || opts.queryCreateInfo === undefined
      || opts.queryCreateInfo === true
    ) {
      option.queryCreateInfo = defaultOption.queryCreateInfo;
    }
    if (opts.queryCreateInfo === false) {
      option.queryCreateInfo = "0";
    }
    return this.$http(option);
  };

  Object.assign($http, imFun.request);
  $http.prototype = imFun.request.prototype;
  Vue.prototype.$http = $http;

  /* 全局accessToken */
  Vue.prototype.$baseAccessToken = () => {
    return accessToken || imFun.getToken();
  };

  /* 全局加载层 */
  Vue.prototype.$baseLoading = function (option) {
    let d = this.$el;
    let loading;
    option = option || {};
    if (!option.index) {
      let opts = {
        lock: true,
        background: "hsla(0,0%,100%,.8)",
        target: d,
      };
      Object.assign(opts, option);
      loading = imFun.Loading.service(opts);
    } else {
      let opts = {
        lock: true,
        spinner: "vab-loading-type" + option.index,
        background: "hsla(0,0%,100%,.8)",
        target: d,
      };
      Object.assign(opts, option);
      loading = imFun.Loading.service(opts);
    }
    return loading;
  };
  /* 全局多彩加载层 */
  Vue.prototype.$baseColorfullLoading = function (index, text) {
    let loading;
    if (!index) {
      loading = imFun.Loading.service({
        lock: true,
        text: text || loadingText,
        spinner: "dots-loader",
        background: "hsla(0,0%,100%,.8)",
        target: this.target,
        fullscreen: true,
      });
    } else {
      switch (index) {
        case 1:
          index = "dots";
          break;
        case 2:
          index = "gauge";
          break;
        case 3:
          index = "inner-circles";
          break;
        case 4:
          index = "plus";
          break;
      }
      loading = imFun.Loading.service({
        lock: true,
        text: text || loadingText,
        spinner: index + "-loader",
        background: "hsla(0,0%,100%,.8)",
        target: this.target,
      });
    }
    return loading;
  };
  /* 全局Message */
  Vue.prototype.$baseMessage = ({ message, type, onClose }) => {
    imFun.Message({
      offset: 60,
      showClose: true,
      message: message,
      type: type,
      dangerouslyUseHTMLString: true,
      duration: messageDuration,
      onClose: onClose,
    });
  };

  /* 全局Alert */
  Vue.prototype.$baseAlert = function (content, title, callback) {
    imFun.MessageBox.alert(content, title || "提示", {
      confirmButtonText: "确定",
      dangerouslyUseHTMLString: true,
      target: this.$el,
      confirmButtonClass: "icondui",
      customClass: "dialog-style",
      callback: (action) => {
        if (callback) {
          callback();
        }
      },
    });
  };

  /* 全局Confirm */
  Vue.prototype.$baseConfirm = function (content, title) {
    return imFun.MessageBox.confirm(content, title || "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      closeOnClickModal: false,
      type: "warning",
      customClass: "dialog-style",
      cancelButtonClass: "iconguanbi",
      confirmButtonClass: "icondui",
    });
  };

  /* 全局Notification */
  Vue.prototype.$baseNotify = (message, title, type, position) => {
    imFun.Notification({
      title: title,
      message: message,
      position: position || "top-right",
      type: type || "success",
      duration: messageDuration,
    });
  };

  /* 全局TableHeight */
  Vue.prototype.$baseTableHeight = (formType) => {
    let height = window.innerHeight;
    let paddingHeight = 400;
    const formHeight = 50;

    if (true) {
      paddingHeight = 365;
    }

    if ("number" === typeof formType) {
      height = height - paddingHeight - formHeight * formType;
    } else {
      height = height - paddingHeight;
    }
    return height;
  };

  /* 全局map图层 */
  Vue.prototype.$baseMap = () => {
    return new maptalks.Map("map", {
      center: [116.41348403785, 39.910843952376],
      zoom: 12,
      minZoom: 1,
      maxZoom: 19,
      spatialReference: {
        projection: "baidu",
      },
      attribution: {
        content: "&copy; vue-admin-beautiful",
      },
      baseLayer: new maptalks.TileLayer("base", {
        cssFilter: "sepia(100%) invert(90%)",
        urlTemplate:
          "http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles=pl&scaler=1&p=1",
        subdomains: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        attribution:
          '&copy; <a target="_blank" href="http://map.baidu.com">Baidu</a>',
      }),
    });
  };

  /* 全局lodash */
  Vue.prototype.$baseLodash = imFun.lodash;
  /* 全局事件总线 */
  Vue.prototype.$baseEventBus = new Vue();

  let typeList = [
    "doc",
    "docx",
    "xls",
    "xlsx",
    "ppt",
    "pptx",
    "csv",
    "wps",
    "dps",
    "et",
    "ett",
    "wpt",
    "vsd",
    "vsdx",
    "wmf",
    "emf",
    "psd",
    "eps",
    "pdf",
    "xmind",
    "obj",
    "3ds",
    "stl",
    "ply",
    "gltf",
    "glb",
    "off",
    "3dm",
    "fbx",
    "dae",
    "wrl",
    "3mf",
    "ifc",
    "brep",
    "step",
    "iges",
    "fcstd",
    "bim",
    "dwg",
    "dxf",
    "dwf",
    "iges",
    "igs",
    "dwt",
    "dng",
    "ifc",
    "dwfx",
    "stl",
    "cf2",
    "plt",
    "txt",
    "xml",
    "md",
    "java",
    "php",
    "py",
    "js",
    "css",
    "zip",
    "rar",
    "jar",
    "tar",
    "gzip",
    "7z",
    "mp3",
    "wav",
    "mp4",
    "flv",
    "avi",
    "rm",
    "mkv",
    "mpeg",
    "mpg",
    "rmvb",
    "wmv",
    "3gp",
    "swf",
    "drawio",
    "tif",
    "tiff",
    "jfif",
    "webp",
    "tga",
    "svg",
    "vue",
  ];
  Vue.prototype.$commonFileUtil = {
    // 文件类型获取与判断接口
    getFileSuffix: function (name) {
      let i = name.lastIndexOf(".");
      if (i < 0) {
        // 默认是文本类型
        return "";
      }
      let suffix = name.substring(i + 1, name.length).toLowerCase();
      return suffix;
    },
    isBinary: function (suffix) {
      if (!suffix || suffix === "") {
        return false;
      }
      let fileTypeMap = {
        bin: true,
        exe: true,
        dll: true,
        so: true,
        lib: true,
        war: true,
        jar: true,
      };
      let type = fileTypeMap[suffix];
      if (undefined === type) {
        return false;
      }
      return true;
    },
    isPicture: function (suffix) {
      if (!suffix || suffix === "") {
        return false;
      }

      let fileTypeMap = {
        jpg: true,
        jpeg: true,
        png: true,
        gif: true,
        bmp: true,
        mpg: true,
        webp: true,
      };

      let type = fileTypeMap[suffix];
      if (undefined === type) {
        return false;
      }

      return true;
    },
    isVideo: function (suffix) {
      if (!suffix || suffix === "") {
        return false;
      }
      let fileTypeMap = {
        avi: true,
        mov: true,
        mpeg: true,
        mpg: true,
        mp4: true,
        rmvb: true,
        asf: true,
        flv: true,
        ogg: true,
      };

      let type = fileTypeMap[suffix];
      if (undefined === type) {
        return false;
      }

      return true;
    },
    isText: function (suffix) {
      if (!suffix || suffix === "") {
        return false;
      }
      let fileTypeMap = {
        txt: true,
        log: true,
        md: true,
        py: true,
        java: true,
        cpp: true,
        hpp: true,
        c: true,
        h: true,
        json: true,
        xml: true,
        html: true,
        sql: true,
        js: true,
        css: true,
        jsp: true,
        php: true,
        properties: true,
        conf: true,
        out: true,
        sh: true,
        bat: true,
        msg: true,
        cmake: true,
        yaml: true,
        yml: true,
      };

      let type = fileTypeMap[suffix];
      if (undefined === type) {
        return false;
      }

      return true;
    },
    isZip: function (suffix) {
      if (!suffix || suffix === "") {
        return false;
      }
      let fileTypeMap = {
        zip: true,
        war: true,
        rar: true,
        "7z": true,
        gz: true,
        tgz: true,
        xz: true,
        txz: true,
        bz2: true,
        tbz2: true,
        tar: true,
      };

      let type = fileTypeMap[suffix];
      if (undefined === type) {
        return false;
      }

      return true;
    },
    isOffice: function (suffix) {
      if (!suffix || suffix === "") {
        return false;
      }
      let fileTypeMap = {
        doc: true,
        docx: true,
        ppt: true,
        pptx: true,
        xls: true,
        xlsx: true,
      };

      let type = fileTypeMap[suffix];
      if (undefined === type) {
        return false;
      }

      return true;
    },
    isPdf: function (suffix) {
      if (!suffix || suffix === "") {
        return false;
      }
      let fileTypeMap = {
        pdf: true,
      };

      let type = fileTypeMap[suffix];
      if (undefined === type) {
        return false;
      }

      return true;
    },
    isPictureFile: function (fileName) {
      if (!fileName) return false;
      let typeStr = Object.prototype.toString.call(fileName);
      let suffix = null;
      if (typeStr === "[object Object]") {
        suffix = this.getFileSuffix(fileName.name);
      } else {
        suffix = this.getFileSuffix(fileName);
      }
      return this.isPicture(suffix);
    },
    isTextFile: function (fileName) {
      let suffix = this.getFileSuffix(fileName);
      return this.isText(suffix);
    },
    getShowUrl(url, showImagePreview) {
      let index = url.lastIndexOf("/");
      let filename;
      if (index >= 0) {
        filename = url.substring(url.lastIndexOf("/") + 1);
      } else {
        filename = url;
      }

      if (this.isPictureFile(filename) && showImagePreview !== false) {
        return url;
      } else {
        return this.getFileIconRequire(filename);
      }
    },
    resolveFileIconName: function (name, showType) {
      let iconType = this.getDiyFileIconType(name) || "other";
      if (showType) {
        iconType = showType;
      }
      return FILE_ICON_NAME_MAP[iconType];
    },
    getFileIconRequire: function (name, showType) {
      return reqImg(this.resolveFileIconName(name, showType));
    },
    getFileIconPath: function (name, showType) {
      return "/resources/images/" + this.resolveFileIconName(name, showType);
    },
    getDiyFileIconType: function (name) {
      let suffix = this.getFileSuffix(name);
      if (suffix === "") {
        // 默认是文本类型
        return "";
      }

      let iconType = FILE_ICON_TYPE_MAP[suffix];
      if (undefined === iconType) {
        return "";
      }
      return iconType;
    },
    getFileExtension(urlString) {
      if (!urlString) return null;
      const url = new URL(urlString);
      // 获取路径部分，例如 "/images/photo.jpg"
      const pathname = url.pathname;

      // 使用 lastIndexOf 找到最后一个点的位置
      const lastDotIndex = pathname.lastIndexOf(".");

      // 如果没有点，或者点在最后一位（即没有后缀），返回空字符串
      if (lastDotIndex === -1 || lastDotIndex === pathname.length - 1) {
        return "";
      }

      // 截取点之后的部分
      return pathname.slice(lastDotIndex + 1).toLowerCase();
    },
    downloadFile: function () {
      let filePath, name;
      let opts;
      if (typeof arguments[0] === "string") {
        filePath = arguments[0];
        name = arguments[1];
      } else {
        opts = arguments[0];
        filePath = opts.filePath;
        name = opts.name;
      }
      if (filePath) {
        let url = null;
        if (filePath.indexOf("?") >= 0) {
          url = filePath + "&_d=true";
        } else {
          url = filePath + "?_d=true";
        }
        if (name) {
          let fileSuffix = this.getFileExtension(filePath);
          if (fileSuffix && !name.endsWith("." + fileSuffix)) {
            name = name + "." + fileSuffix;
          }

          url += "&_n=" + encodeURIComponent(name);
        }
        // window.open(url);
        openInNewTab(url);
      }
    },
    isPreviewFile(fileName) {
      let fileSuffix = this.getFileSuffix(fileName);
      return typeList.includes(fileSuffix);
    },
  };

  Vue.prototype.$openFilePreview = function () {
    let filePath;
    let opts;
    if (typeof arguments[0] === "string") {
      filePath = arguments[0];
    } else {
      let attachment = arguments[0];
      filePath = attachment.domain + attachment.url;
    }
    let fileSuffix = this.$commonFileUtil.getFileSuffix(filePath);
    if (!typeList.includes(fileSuffix)) {
      return;
    }

    this.$http({
      url: USER_PREFIX + "/sf_common/getFilePreviewUrl",
      method: `post`,
      data: {
        url: filePath,
      },
      isLoading: true,
      success: (res) => {
        if (res.objx) {
          openInNewTab(res.objx);
        }
      },
    });
  };

  function openInNewTab(url) {
    if (!url) return;
    let a = document.createElement("a");
    a.href = url;
    a.target = "_blank";
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  }

  Vue.prototype.$getFilePreviewUrl = async function (obj, callback) {
    let filePath;
    let opts;
    if (typeof obj === "string") {
      filePath = obj;
    } else {
      let attachment = obj;
      filePath = attachment.domain + attachment.url;
    }
    let fileSuffix = this.$commonFileUtil.getFileSuffix(filePath);
    /*if (!typeList.includes(fileSuffix)) {
      return;
    }*/

    return this.$http({
      url: USER_PREFIX + "/sf_common/getFilePreviewUrl",
      method: `post`,
      data: {
        url: filePath,
      },
      isLoading: true,
      success: (res) => {
        callback && callback(res.objx);
      },
    });
  };

  Vue.prototype.$baseFilePreview = function (attachment, index) {
    let that = this;
    let openImagePreView = function (attachments, index) {
      let pictureIndex = -1;
      let pictureDtoList = [];
      index = index || 0;
      attachments.forEach((item, i) => {
        let typeStr = Object.prototype.toString.call(item);
        if (typeStr === "[object Object]") {
          if (that.$commonFileUtil.isPictureFile(item.url)) {
            if (i <= index) {
              pictureIndex++;
            }
            pictureDtoList.push(item.domain + item.url);
          }
        } else {
          if (that.$commonFileUtil.isPictureFile(item)) {
            if (i <= index) {
              pictureIndex++;
            }
            pictureDtoList.push(item);
          }
        }
      });

      let a = Vue.extend(ElImageViewer);
      let instance = new a({
        propsData: {
          onClose: () => {
            dom.remove();
          },
          initialIndex: pictureIndex,
          urlList: pictureDtoList,
        },
      });
      let dom = instance.$mount().$el;
      document.body.append(dom);
    };
    let openPreview = function (attachment, index) {
      if (Array.isArray(attachment)) {
        let currentFile = attachment[index];
        let typeStr = Object.prototype.toString.call(currentFile);
        let url
          = typeStr === "[object Object]"
            ? currentFile.domain + currentFile.url
            : currentFile;
        if (that.$commonFileUtil.isPictureFile(url)) {
          openImagePreView(attachment, index);
        } else if (that.$commonFileUtil.isPreviewFile(url)) {
          that.$openFilePreview(url);
        }
      } else {
        let typeStr = Object.prototype.toString.call(attachment);
        let url
          = typeStr === "[object Object]"
            ? attachment.domain + attachment.url
            : attachment;
        if (that.$commonFileUtil.isPictureFile(url)) {
          openImagePreView([url], 0);
        } else if (that.$commonFileUtil.isPreviewFile(url)) {
          that.$openFilePreview(url);
        }
      }
    };
    openPreview(attachment, index);
  };

  Vue.prototype.$openEditView = function (key) {
    this[key] = false;
    setTimeout(() => {
      this[key] = true;
    }, 200);
  };

  Vue.prototype.$baseReload = function (param) {
    this.$emit("reload", this, param);
  };

  Vue.prototype.$reloadHandle = function (target, param) {
    let visibleKey = target.$attrs["visible-key"] || "showEdit";
    let parentTarget = target.$attrs["parent-target"] || target.$parent;
    let originTarget = parentTarget.$refs._viewDialog ? parentTarget : target;
    let updateParam
      = param !== null
      && param !== undefined
      && param.updateParam !== null
      && param.updateParam !== undefined
        ? param.updateParam
        : {};
    for (let key in updateParam) {
      originTarget.$emit("update:" + key, updateParam[key]);
    }
    parentTarget[visibleKey] = false;
    setTimeout(() => {
      parentTarget[visibleKey] = true;
    }, 200);
  };

  Vue.prototype.$baseStartPickerOptions = function (value, type) {
    return {
      disabledDate: (time) => {
        if (value !== null && value !== undefined && value !== "") {
          let date = new Date(value.replace(/-/g, "/"));
          if (!type || type === "date") {
            date.setDate(date.getDate() + 1);
            return time.getTime() >= date.getTime();
          } else if (type === "year") {
            return time.getYear() > date.getYear();
          } else if (type === "month") {
            date.setMonth(date.getMonth() + 1);
            return time.getTime() >= date.getTime();
          }
        } else {
          return false;
        }
      },
    };
  };

  Vue.prototype.$baseEndPickerOptions = function (value, format) {
    return {
      disabledDate: (time) => {
        if (value !== null && value !== undefined && value !== "") {
          let date = new Date(value.replace(/-/g, "/"));
          return time.getTime() < date.getTime();
        } else {
          return false;
        }
      },
    };
  };

  //除法
  function baseDiv() {
    let value = 0;
    if (arguments.length) {
      value = arguments[0];
      for (let i = 1; i < arguments.length; i++) {
        value = XEUtils.divide(value, arguments[i]);
      }
    }
    return value;
  }

  //乘法
  function baseMul() {
    let value = 0;
    if (arguments.length) {
      value = arguments[0];
      for (let i = 1; i < arguments.length; i++) {
        value = XEUtils.multiply(value, arguments[i]);
      }
    }
    return value;
  }

  //加法
  function baseAdd() {
    let value = 0;
    if (arguments.length) {
      value = arguments[0];
      for (let i = 1; i < arguments.length; i++) {
        value = XEUtils.add(value, arguments[i]);
      }
    }
    return value;
  }

  //减法
  function baseSub() {
    let value = 0;
    if (arguments.length) {
      value = arguments[0];
      for (let i = 1; i < arguments.length; i++) {
        value = XEUtils.subtract(value, arguments[i]);
      }
    }
    return value;
  }

  Vue.prototype.$baseAdd = baseAdd;
  Vue.prototype.$baseSub = baseSub;
  Vue.prototype.$baseMul = baseMul;
  Vue.prototype.$baseDiv = baseDiv;

  /**
   * 格式化数字为带千分位的字符串。
   *
   * @param {string | number} value - 输入值
   * @param {Object} [options={}] - 配置
   * @param {boolean} [options.fixed=false] -
   *   - `true`: 启用定点精度处理 —— 使用 toFixed(digits) 四舍五入并补零到指定小数位。
   *   - `false`（默认）: 保留原始小数形式（不四舍五入、不补零、保留尾随零）。
   * @param {number} [options.digits=2] - 小数位数（仅在 fixed: true 时生效）
   * @param {string} [options.thousandsSeparator=','] - 千分位分隔符（始终生效）
   * @param {string} [options.decimalSeparator='.'] - 小数点符号
   * @returns {string}
   *
   * @example
   * // 默认：保留原始小数
   * formatNumber(0.2);                         // "0.2"
   * formatNumber("0.2000");                    // "0.2000"
   *
   * // 启用定点精度处理
   * formatNumber(0.2, { fixed: true });               // "0.20"
   * formatNumber("123.456", { fixed: true, digits: 1 }); // "123.5"
   * formatNumber(1000, { fixed: true, digits: 0 });   // "1,000"
   */
  function formatNumber(value, options = {}) {
    if (value === null || value === undefined || value === "") {
      return "";
    }

    const {
      fixed = false,
      digits = 2,
      thousandsSeparator = ",",
      decimalSeparator = ".",
    } = options;

    const isNumber = typeof value === "number";
    let str = String(value).trim();

    // Normalize ".123" → "0.123"
    if (str.charCodeAt(0) === 46) {
      str = "0" + str;
    } else if (str.startsWith("-.")) {
      str = "-0." + str.slice(2);
    }

    let intPart, decPart, isNegative;

    if (fixed) {
      // ✅ 启用精度处理：toFixed + 补零
      const num = isNumber ? value : parseFloat(str);
      if (num !== num) return str;

      const fixedStr = num.toFixed(digits);
      const dotIndex = fixedStr.indexOf(".");
      intPart = dotIndex === -1 ? fixedStr : fixedStr.slice(0, dotIndex);
      decPart = dotIndex === -1 ? "" : fixedStr.slice(dotIndex + 1);
      isNegative = intPart.charCodeAt(0) === 45;
      if (isNegative) intPart = intPart.slice(1);
    } else {
      // 保留原始小数
      let s = str;
      isNegative = s.charCodeAt(0) === 45;
      if (isNegative) s = s.slice(1);

      const dotIndex = s.indexOf(".");
      intPart = dotIndex === -1 ? s : s.slice(0, dotIndex);
      decPart = dotIndex === -1 ? "" : s.slice(dotIndex + 1);

      if (intPart === "") intPart = "0";
      if (!/^\d+$/.test(intPart)) return str;
    }

    // 千分位（始终应用）
    let fmtInt = intPart;
    if (intPart !== "0") {
      let out = "";
      for (let i = intPart.length - 1, c = 0; i >= 0; i--, c++) {
        if (c > 0 && c % 3 === 0) out = thousandsSeparator + out;
        out = intPart[i] + out;
      }
      fmtInt = out;
    }

    // 拼接
    let result = isNegative ? "-" + fmtInt : fmtInt;
    if (decPart) {
      result += decimalSeparator + decPart;
    } else if (fixed && digits > 0) {
      result += decimalSeparator + "0".repeat(digits);
    }

    return result;
  }
  Vue.prototype.$formatNumber = formatNumber;

  /**
   * 生成一个符合 RFC4122 标准的随机 UUID (v4)
   * @returns {string} 格式为 "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" 的 UUID 字符串
   */
  function generateUUID() {
    const buf = new Uint8Array(16);
    crypto.getRandomValues(buf);
    buf[6] = (buf[6] & 0x0f) | 0x40; // version 4
    buf[8] = (buf[8] & 0x3f) | 0x80; // variant RFC4122
    const hex = Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join(
      ""
    );
    return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(
      12,
      16
    )}-${hex.slice(16, 20)}-${hex.slice(20)}`;
  }
  Vue.prototype.$generateUUID = generateUUID;

  //数字精确位数
  Vue.prototype.$currency = function (value, priceScale, priceRoundType) {
    if (value !== null && value !== undefined) {
      if (priceScale === null || priceScale === undefined) {
        priceScale = 2;
      }
      if (priceRoundType === null || priceRoundType === undefined) {
        priceRoundType = "roundHalfUp";
      }
      let price;
      if (priceRoundType === "roundHalfUp") {
        price = (
          Math.round(value * Math.pow(10, priceScale))
          / Math.pow(10, priceScale)
        ).toFixed(priceScale);
      } else if (priceRoundType === "roundUp") {
        price = (
          Math.ceil(value * Math.pow(10, priceScale)) / Math.pow(10, priceScale)
        ).toFixed(priceScale);
      } else {
        price = (
          Math.floor(value * Math.pow(10, priceScale))
          / Math.pow(10, priceScale)
        ).toFixed(priceScale);
      }
      return price;
    }
  };

  Vue.prototype.$getBaseDicts = async function (option) {
    let isLoading = option.isLoading || false;
    return this.$http({
      url: USER_PREFIX + "/common_attribute/listItems",
      method: `post`,
      data: {
        code: option.code,
        enabled: true,
        forCompany: true,
        ...option.data,
      },
      isLoading: isLoading,
      modalStrictly: true,
      success: (res) => {
        let dicts = res.objx || [];
        let dictMap = {};
        for (let item of dicts) {
          dictMap[item.sn] = item.value;
        }
        /* dicts.forEach((item) => {
          dictMap[item.sn] = item.value;
        }); */
        option.success
          && option.success({
            dicts,
            dictMap,
          });
      },
    });
  };

  imFun.Form.methods.$baseValidate = function (callback, opt) {
    let that = this;
    that.validate((valid, obj, c, d) => {
      if (!valid && (!opt || opt.errorTip !== false)) {
        this.$message({
          message: this.$t2("必填项不能为空", "system.message.required"),
          type: "error",
          duration: 2000,
        });
      }
      scrollToFirstError(that);
      callback(valid, obj);
    });
  };

  function scrollToFirstError(formTarget) {
    // 获取第一个验证失败的字段
    // let formTarget = this.$refs['renderForm'];
    const firstErrorField = Object.keys(formTarget.fields).find((key) => {
      return formTarget.fields[key].validateState === "error";
    });

    if (firstErrorField) {
      const field = formTarget.fields[firstErrorField];

      let dom = field.$el;
      if (dom) {
        // 滚动到该字段位置
        dom.scrollIntoView({
          behavior: "smooth",
          block: "center",
        });

        // 添加高亮效果
        dom.classList.add("highlight");

        // 3秒后移除高亮效果
        setTimeout(() => {
          dom.classList.remove("highlight");
        }, 3000);
      }
    }
  }

  Vue.prototype.$getBillInfo = async function (option) {
    let defaultOption = {
      url: null,
      method: `post`,
      data: {},
      isLoading: true,
      modalStrictly: true,
      success: null,
    };
    let opt = Object.assign({}, defaultOption, option);
    delete opt.wfConfig;
    return this.$http({
      ...opt,
      success: (res, response) => {
        option.success && option.success(res, response);
      },
    });
  };

  Vue.prototype.$downloadByFileWhole = function (fileWhole, fileName) {
    let that = this;
    if (!fileWhole) {
      this.$baseAlert("凭证信息不存在");
      return;
    }
    let getDownloadDomian = function (callback) {
      that.$http({
        method: "post",
        url: USER_PREFIX + "/common/fileDownloadUrl",
        data: {},
        isLoading: true,
        success: (res) => {
          callback(res.objx);
        },
      });
    };
    getDownloadDomian((domain) => {
      if (fileName) {
        fileWhole.fileName = fileName;
      }
      that.$http({
        method: "post",
        url: domain + "/docfile/download",
        data: fileWhole,
        isLoading: true,
        success: (res) => {
          // window.open(res.objx.url);
          let url = res.objx.url;
          openInNewTab(url);
        },
      });
    });
  };

  let isDef = function (value) {
    return value !== undefined && value !== null;
  };

  Vue.prototype.$t2 = function (defaultValue, path, values) {
    let that = window.$vueRoot;
    if (!that.hasOwnProperty("_i18n")) {
      return defaultValue;
    }
    const i18n = that.$i18n;
    path = path || defaultValue;
    return i18n.te(path) ? i18n.t(path, values) : defaultValue;
  };

  Vue.prototype.$t1 = function (path, values) {
    let that = window.$vueRoot;
    if (!that.hasOwnProperty("_i18n")) {
      return path;
    }
    let lang = that.$i18n.locale;
    const i18n = that.$i18n;
    if (lang === "zh") {
      let val = i18n._t(path, lang, { zh: { [path]: path } }, null, values);
      return val;
    } else {
      if (!i18n.te(path)) {
        return i18n._t(path, lang, { zh: { [path]: path } }, null, values);
      } else {
        return (
          i18n.t(path, values)
          || i18n._t(path, lang, { zh: { [path]: path } }, null, values)
        );
      }
    }
  };

  Vue.prototype.$i18nVal = function (zhValue, enValue) {
    let that = window.$vueRoot;
    if (!that.hasOwnProperty("_i18n")) {
      return zhValue;
    }
    let $i18n = that.$i18n;
    let value = zhValue;
    if ($i18n.locale === "zh") {
      value = zhValue;
    } else if ($i18n.locale === "en") {
      value = enValue;
    }
    return value;
  };

  Vue.prototype.$utcToLocal = function (utcTime) {
    if (!utcTime) return utcTime;
    let offsetHours = this.$store.getters.utcTransformOffset; // 时区偏移量，单位：小时
    if (!offsetHours || offsetHours === 0) return utcTime;
    let localTime = moment(utcTime).add(offsetHours, "hours");
    return localTime.format("YYYY-MM-DD HH:mm:ss");
  };

  Vue.prototype.$window = window;
};

window && Object.assign(window, imFun.prefixConfig);
if (typeof window !== "undefined" && window.Vue) {
  install(window.Vue);
}

export default install;
