| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- import { Base64 } from "js-base64";
- // 节流
- export const throttle = <T extends (...args: any) => any>(fn: T, delay: number = 160) => {
- let previous = 0;
- return function <Args extends Array<any>, This>(this: This, ...args: Parameters<T>) {
- const now = Date.now();
- if (now - previous >= delay) {
- fn.apply(this, args);
- previous = now;
- }
- };
- };
- // 防抖
- export const debounce = <T extends (...args: any) => any>(fn: T, delay: number = 160) => {
- let timeout: any;
- return function <This>(this: This, ...args: Parameters<T>) {
- clearTimeout(timeout);
- timeout = setTimeout(() => {
- fn.apply(this, args);
- }, delay);
- };
- };
- const place = /(?:\/:([^/]*))/g;
- // 匹配 /:id 是否匹配某个url
- export const equalUrl = (tempUrl: string, url: string) => {
- const urlRgStr =
- "^" +
- tempUrl.replace(/\/([^:])/g, (_, d) => `\\/${d}`).replace(place, () => `(?:/[^/]*)`) +
- "$";
- return new RegExp(urlRgStr).test(url);
- };
- // 生成/:id 类真实url
- export const gendUrl = (tempUrl: string, params: { [key: string]: any }) => {
- let url = "";
- let preIndex = 0;
- let m;
- while ((m = place.exec(tempUrl))) {
- url += tempUrl.substring(preIndex, m.index + 1) + (params[m[1]] || "null");
- preIndex = m.index + m[0].length;
- }
- url += tempUrl.substr(preIndex);
- return url;
- };
- // 匹配一组数组是否是path链接
- export const includesUrl = (tempUrls: Array<string> | readonly string[], url: string) =>
- tempUrls.some((tempUrl) => equalUrl(tempUrl, url));
- // 字符串转params对象
- export const strToParams = (str: string) => {
- if (str[0] === "?") {
- str = str.substr(1);
- }
- const result: { [key: string]: string } = {};
- const splitRG = /([^=&]+)(?:=([^&]*))?&?/;
- let rgRet;
- while ((rgRet = str.match(splitRG))) {
- result[rgRet[1]] = rgRet[2] === undefined ? true : rgRet[2];
- str = str.substr(rgRet[0].length);
- }
- return result;
- };
- // 对象转params
- export const paramsToStr = (params: { [key: string]: string | boolean }) =>
- "?" +
- Object.keys(params)
- .filter((key) => params[key] !== undefined)
- .map((key) => `${key}${params[key] == false ? "" : `=${params[key]}`}`)
- .join("&");
- export const objectToString = Object.prototype.toString;
- export const toTypeString = (value: unknown): string => objectToString.call(value);
- export const toRawType = (value: unknown): string => {
- // extract "RawType" from strings like "[object RawType]"
- return toTypeString(value).slice(8, -1);
- };
- export const isString = <T>(value: T): T extends string ? true : false =>
- (toRawType(value) === "String") as any;
- // 递归复制
- export const recursionCopy = <
- T extends object | Array<any>,
- R extends object | Array<any>
- >(
- from: R,
- to: T
- ): T & R => {
- if (toRawType(from) !== toRawType(to)) {
- return to as T & R;
- }
- const toKeys = Object.keys(to);
- const fromKeys = Object.keys(from);
- const result = toRawType(from) === "Array" ? [...(from as Array<any>)] : { ...from };
- for (const toKey of toKeys) {
- const toItem = (to as any)[toKey];
- let i = 0;
- for (; i < fromKeys.length; i++) {
- const fromKey = fromKeys[i];
- if (toKey === fromKey) {
- const fromItem = (from as any)[fromKey];
- const fromItemType = toRawType(fromItem);
- const toItemType = toRawType(toItem);
- if (
- fromItemType === toItemType &&
- (fromItemType === "Object" || fromItemType === "Array")
- ) {
- (result as any)[fromKey] = recursionCopy(fromItem, toItem);
- } else {
- (result as any)[fromKey] = toItem;
- }
- break;
- }
- }
- if (i === fromKeys.length) {
- (result as any)[toKey] = toItem;
- }
- }
- return result as T & R;
- };
- // 日期格式化
- export const formatDate = (date: Date, fmt: string = "yyyy-MM-dd hh:mm") => {
- const map = {
- "M+": date.getMonth() + 1, //月份
- "d+": date.getDate(), //日
- "h+": date.getHours(), //小时
- "m+": date.getMinutes(), //分
- "s+": date.getSeconds(), //秒
- "q+": Math.floor((date.getMonth() + 3) / 3), //季度
- S: date.getMilliseconds(), //毫秒
- };
- if (/(y+)/.test(fmt)) {
- fmt = fmt.replace(
- RegExp.$1,
- date
- .getFullYear()
- .toString()
- .substr(4 - RegExp.$1.length)
- );
- }
- (Object.keys(map) as Array<keyof typeof map>).forEach((k) => {
- if (new RegExp("(" + k + ")").test(fmt)) {
- const val = map[k].toString();
- fmt = fmt.replace(
- RegExp.$1,
- RegExp.$1.length === 1 ? val : ("00" + val).substr(val.length)
- );
- }
- });
- return fmt;
- };
- // 函数调用拦截
- export const funIntercept = <T extends (...args: any) => any>(
- originFun: T,
- proxyFun: (args: Parameters<T>, result: ReturnType<T>) => void
- ): T =>
- function (...args: Parameters<T>) {
- const result = originFun.apply(this, args);
- proxyFun(args, result);
- return result;
- } as T;
- // 四舍五入保留指定位数
- export const round = (num: number, index: number = 2) => {
- const s = Math.pow(10, index);
- return Math.round(num * s) / s;
- };
- // setTimeout转promise
- export const asyncTimeout = (mis: number = 0) =>
- new Promise((resolve) => setTimeout(resolve, mis));
- // 持续检查直到通过
- export const checkPromise = <T = any>(check: () => T) => {
- return new Promise<T>((resolve) => {
- const interval = setInterval(() => {
- const result = check();
- if (!!result) {
- clearInterval(interval);
- resolve(result);
- }
- }, 16);
- });
- };
- // 下载文件
- // export const downFile = (url: string, name?: string) => {
- // console.log(saveAs(url, name))
- // // const el = document.createElement('a')
- // // el.setAttribute('download', name)
- // // el.setAttribute('href', url)
- // // el.click()
- // }
- export const copyText = async (text: string, fallback?: boolean) => {
- if (navigator.clipboard && !fallback) {
- let permiss;
- try {
- let permiss = await navigator.permissions.query({ name: "geolocation" });
- permiss.state === "denied";
- } catch (e) {
- console.error(e);
- }
- if (permiss && permiss.state === "denied") {
- console.error(permiss);
- throw new Error("请授予写入粘贴板权限!");
- } else {
- try {
- await navigator.clipboard.writeText(text);
- } catch (e) {
- console.error("不支持navigator.clipboard.writeText 开启回退");
- return await copyText(text, true);
- }
- }
- } else {
- const textarea = document.createElement("textarea");
- document.body.appendChild(textarea);
- // 隐藏此输入框
- textarea.style.position = "fixed";
- textarea.style.clip = "rect(0 0 0 0)";
- textarea.style.top = "10px";
- // 赋值
- textarea.value = text;
- // 选中
- textarea.select();
- // 复制
- document.execCommand("copy", true);
- // 移除输入框
- document.body.removeChild(textarea);
- }
- };
- // 是否修改
- const _inRevise = (raw1, raw2, readly: Set<[any, any]>) => {
- if (raw1 === raw2) return false;
- const rawType1 = toRawType(raw1);
- const rawType2 = toRawType(raw2);
- if (rawType1 !== rawType2) {
- return true;
- } else if (rawType1 === "String" || rawType1 === "Number" || rawType1 === "Boolean") {
- if (rawType1 === "Number" && isNaN(raw1) && isNaN(raw2)) {
- return false;
- } else {
- return raw1 !== raw2;
- }
- }
- const rawsArray = Array.from(readly.values());
- for (const raws of rawsArray) {
- if (raws.includes(raw1) && raws.includes(raw2)) {
- return false;
- }
- }
- readly.add([raw1, raw2]);
- if (rawType1 === "Array") {
- return (
- raw1.length !== raw2.length ||
- raw1.some((item1, i) => _inRevise(item1, raw2[i], readly))
- );
- } else if (rawType1 === "Object") {
- const rawKeys1 = Object.keys(raw1).sort();
- const rawKeys2 = Object.keys(raw2).sort();
- return (
- _inRevise(rawKeys1, rawKeys2, readly) ||
- rawKeys1.some((key) => _inRevise(raw1[key], raw2[key], readly))
- );
- } else if (rawType1 === "Map") {
- const rawKeys1 = Array.from(raw1.keys()).sort();
- const rawKeys2 = Array.from(raw2.keys()).sort();
- return (
- _inRevise(rawKeys1, rawKeys2, readly) ||
- rawKeys1.some((key) => _inRevise(raw1.get(key), raw2.get(key), readly))
- );
- } else if (rawType1 === "Set") {
- return inRevise(Array.from(raw1.values()), Array.from(raw2.values()));
- } else {
- return raw1 !== raw2;
- }
- };
- export const inRevise = (raw1, raw2) => _inRevise(raw1, raw2, new Set());
- function randomWord(randomFlag, min, max?: number) {
- let str = "";
- let range = min;
- let arr = [
- "0",
- "1",
- "2",
- "3",
- "4",
- "5",
- "6",
- "7",
- "8",
- "9",
- "a",
- "b",
- "c",
- "d",
- "e",
- "f",
- "g",
- "h",
- "i",
- "j",
- "k",
- "l",
- "m",
- "n",
- "o",
- "p",
- "q",
- "r",
- "s",
- "t",
- "u",
- "v",
- "w",
- "x",
- "y",
- "z",
- "A",
- "B",
- "C",
- "D",
- "E",
- "F",
- "G",
- "H",
- "I",
- "J",
- "K",
- "L",
- "M",
- "N",
- "O",
- "P",
- "Q",
- "R",
- "S",
- "T",
- "U",
- "V",
- "W",
- "X",
- "Y",
- "Z",
- ];
- // 随机产生
- if (randomFlag) {
- range = Math.round(Math.random() * (max - min)) + min;
- }
- for (var i = 0; i < range; i++) {
- let pos = Math.round(Math.random() * (arr.length - 1));
- str += arr[pos];
- }
- return str;
- }
- /**
- * 密码加密
- * @param {String} pwd
- */
- export function encodePassword(str: string, strv = "") {
- str = Base64.encode(str);
- const NUM = 2;
- const front = randomWord(false, 8);
- const middle = randomWord(false, 8);
- const end = randomWord(false, 8);
- let str1 = str.substring(0, NUM);
- let str2 = str.substring(NUM);
- if (strv) {
- let strv1 = strv.substring(0, NUM);
- let strv2 = strv.substring(NUM);
- return [front + str2 + middle + str1 + end, front + strv2 + middle + strv1 + end];
- }
- return front + str2 + middle + str1 + end;
- }
- export const normalizeLink = (link: string): string => {
- if (!link.includes("//")) {
- return location.protocol + "//" + link;
- } else {
- return link;
- }
- };
- // 加载第三方库
- export const loadLib = (() => {
- const cache = {};
- const load = (lib: string, success, err, maxReq = 0) => {
- const el = document.createElement("script");
- el.src = lib;
- document.body.appendChild(el);
- el.onload = success;
- el.onerror = () => {
- if (maxReq > 0) {
- load(lib, success, err, --maxReq);
- } else {
- err();
- }
- };
- };
- return (lib: string) => {
- if (!cache[lib]) {
- cache[lib] = new Promise((resolve, reject) => {
- load(lib, resolve, reject, 3);
- });
- }
- return cache[lib];
- };
- })();
- export const numberSplice = (val: number) => {
- const integer = Math.floor(val);
- const decimal = val - integer;
- return [integer, decimal];
- };
- //经纬度转度°分′秒″
- export const toDegrees = (val: number, retain = 4) => {
- let temps = numberSplice(val);
- const d = temps[0];
- temps = numberSplice(temps[1] * 60);
- const m = temps[0];
- const s = round(temps[1] * 60, retain);
- return `${d}°${m}′${s}″`;
- };
- export const DMSRG = /(\d+)°(\d+)′(\d+|\d+.\d+)″$/;
- export const dmsCheck = (dms: string) => {
- const r = DMSRG.exec(dms);
- return r && Number(r[2]) < 60 && Number(r[3]) < 60;
- };
- // 度分秒转经纬度
- export const toDigital = (dms: string, retain = 6) => {
- const r = DMSRG.exec(dms);
- if (r) {
- return round(Number(r[1]) + Number(r[2]) / 60 + Number(r[3]) / 3600, 12);
- }
- };
- export const addImmobilityClick = (
- dom: HTMLElement,
- handler: (ev?: MouseEvent) => any
- ) => {
- const mousedownHandler = (ev: MouseEvent) => {
- const dx = ev.offsetX;
- const dy = ev.offsetY;
- dom.addEventListener("mouseup", function upHandler(ev) {
- const ux = ev.offsetX;
- const uy = ev.offsetY;
- if (Math.abs(dx - ux + (dy - uy)) < 5) {
- handler(ev);
- }
- });
- };
- dom.addEventListener("mousedown", mousedownHandler);
- return () => dom.removeEventListener("mousedown", mousedownHandler);
- };
- export const firstUpperCase = (str: string) => {
- return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
- };
- export * from "./file-serve";
- export * from "./vue";
- export * from "./graph";
- export const base64ToBlob = (base64Data: string) => {
- let arr = base64Data.split(",");
- let matchs = arr[0].match(/:(.*?);/);
- if (!matchs) {
- return null;
- }
- let fileType = matchs[1];
- let bstr = atob(arr[1]),
- l = bstr.length,
- u8Arr = new Uint8Array(l);
- while (l--) {
- u8Arr[l] = bstr.charCodeAt(l);
- }
- return new Blob([u8Arr], {
- type: fileType,
- });
- };
- export const blobToBase64 = (blob: Blob) => {
- return new Promise<string>((resolve, reject) => {
- const fileReader = new FileReader();
- fileReader.onload = (e) => {
- resolve(e.target.result as string);
- };
- // readAsDataURL
- fileReader.readAsDataURL(blob);
- fileReader.onerror = () => {
- reject(new Error('blobToBase64 error'));
- };
- });
- }
- export const getId = () => {
- return (new Date()).getTime().toString() + Math.ceil(Math.random() * 1000).toString()
- }
|