/** * 数据工具类 * @author BrightLi * @since 2020/5/3 */ import path from "path"; import fs from "fs"; import SKLogger from "./SKLogger"; import {util} from "protobufjs"; import float = util.float; export default class SKDataUtil { // 生成UUID static uuid(): string { if (typeof (window) !== "undefined" && typeof (window.crypto) !== "undefined" && typeof (window.crypto.getRandomValues) !== "undefined") { let buf: Uint16Array = new Uint16Array(8); window.crypto.getRandomValues(buf); let result = (this.pad4(buf[0]) + this.pad4(buf[1]) + this.pad4(buf[2]) + this.pad4(buf[3]) + this.pad4(buf[4]) + this.pad4(buf[5]) + this.pad4(buf[6]) + this.pad4(buf[7])); return result; } else { let result = this.random4() + this.random4() + this.random4() + this.random4()+ this.random4() + this.random4() + this.random4() + this.random4(); return result; } } static primaryKey(): string { let uuid = SKDataUtil.uuid(); let count = SKDataUtil.random(1,5); for (let i = 0; i < count; i++) { let index = SKDataUtil.random(1, uuid.length) let split = uuid.split(""); split.splice(index, 1); uuid = split.join(""); } return uuid; } static rolePrimaryKey(number: any): any { let num = ''; for (let i = 0; i < number; i++) { if (i == 0) { num += Math.floor(Math.random() * 9 + 1); } else { num += Math.floor(Math.random() * 10); } } return parseInt(num); } private static pad4(num: number): string { let ret: string = num.toString(16); while (ret.length < 4) { ret = "0" + ret; } return ret; } private static random4(): string { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); } // 随机数 static random(min: number, max: number): number { return Math.floor(Math.random() * (max - min + 1)) + min; } // 从数组中随机抽取一项 static randomList(value: any[]): any { if (value == null || value.length < 1) { return null; } let index = this.random(0, value.length - 1); return value[index]; } // 数组洗牌 static shuffle(value: any[]): any[] { if (!Array.isArray(value)) { return null; } let result = this.clone(value); let j: number; for (let i = result.length - 1; i > 0; i--) { j = Math.floor(Math.random() * (i + 1)); [result[i], result[j]] = [result[j], result[i]]; } return result; } static randomListBy(list: any[], total: number): any[] { if (list == null || list.length < total) { return []; } list = this.clone(list); let result = []; for (let i = 0; i < total; i++) { let random = Math.floor(Math.random() * list.length); result.push(list.splice(random, 1)[0]); } return result; } // 替换指定位置的字符 static replaceChar(value: string, index: number, char: string): string { return value.substr(0, index) + char + value.substr(index + char.length); } // 从前查找相同字符出现的最后一个位置 static sameIndex(value: string, char: string): number { var result: number = -1; for (var i = 0; i < value.length; i++) { if (value[i] == char) { if (result == -1) { result = i; } else { result++; } } else if (result != -1) { break; } } return result; } // 从后查找相同字符出现的最后一个位置 static sameLastIndex(value: string, char: string): number { var result: number = -1; for (var i = value.length - 1; i > 0; i--) { if (value[i] == char) { if (result == -1) { result = i; } else { result--; } } else if (result != -1) { break; } } return result; } // 格式化数字,不足位补0 static prefixInteger(num: number, length: number): string { let result = (Array(length).join('0') + num).slice(-length); return result; } // "YYYY-mm-dd HH:MM" static formatDate(format: string, value: string): string { let now = new Date(value); let opt: any = { "Y+": now.getFullYear().toString(), "m+": (now.getMonth() + 1).toString(), "d+": now.getDate().toString(), "H+": now.getHours().toString(), "M+": now.getMinutes().toString(), "S+": now.getSeconds().toString(), } let result: RegExpExecArray; for (let key in opt) { result = new RegExp(`(${key})`).exec(format); if (result) { format = format.replace(result[1], (result[1].length == 1) ? (opt[key]) : (opt[key].padStart(result[1].length, "0"))); } } return format; } // 根据ID生成5位邀请码 static encodeInvite(value: number) { let key = 'E50CDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ'; let result = ""; while (value > 0) { let mod = value % 35; value = (value - mod) / 35; result = key[mod] + result; } if (result.length < 5) { result = "F" + result; let len = result.length; let min = 0; let max = key.length - 1; for (let i = len; i < 5; i++) { let index = Math.floor(Math.random() * (max - min + 1)) + min; result = key[index] + result; } } return result; } // 解码邀请码 static decodeInvite(value: string): number { let key = 'E50CDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ'; let index = value.indexOf("F"); if (index != -1) { value = value.slice(index + 1, value.length); } let result = 0; let p = 0; for (let i = value.length - 1; i >= 0; i--) { let char = value[i]; index = key.indexOf(char); if (index != -1) { result += index * Math.pow(35, p); p++; } } return result; } // 从数组中获得匹配 static numberByList(list: any[], key: string, value: number, targetKey: string): any { for (let item of list) { let temp = item[key]; if (!temp) { continue; } if (temp == value) { let result = item[targetKey]; return result; } } return null; } // 从数组中获得匹配 static datalist(list: any[], key: string): any { for (let item of list) { if (item == key) { return item; } } return null; } //随机从数组中取出一条数据 static radom(array: any,start: number = 1){ let end: number = array.length; // end不传为数组长度 start--; const index = start + Math.floor(Math.random() * (end - start)); return array[index]; } // 是否存在KV static hasKVByList(list: any[], key: string, value: any): boolean { for (let item of list) { if (item[key] == value) { return true; } } return false; } // 是否有互斥 static hasMutex(target: any[], mutex: any[], mutexKey: string, key: string): boolean { for (let item of target) { let temp = item[key]; if (!temp) { continue; } // 如果是互斥数组 if (Array.isArray(temp)) { for (let b of mutex) { for (let a of temp) { if (item[key] == b) { return true; } } } } else { for (let b of mutex) { if (temp == b) { return true; } } } } return false; } // 获得二维数组中的数值 static intOf2Array(list: number[][], one: number, two: number, valid: number): number { if (!list) { return valid; } if (one < 0 || one >= list.length) { return valid; } let temp = list[one] as number[]; if (!temp) { return valid; } if (two < 0 || two >= temp.length) { return valid; } return temp[two]; } // 根据概率返回真假 static probability(min: number, max: number): boolean { let result = SKDataUtil.random(min, max); if (result <= min) { return true; } else { return false; } } static dictByDict(target: any, sheet: any, key: any): any { if (!target) { return null; } let dict = target[sheet]; if (!dict) { return null; } let result = dict[key]; return result; } static findByDict(target: any, targetKey: any, value: any, resultKey: any, valid: any): any { if (!target) { return valid; } for (let key in target) { let item = target[key]; if (item[targetKey] == value) { return item[resultKey]; } } return valid; } static numberByString(target: string, splitter: string, index: number, valid: number = 0): number { if (!target) { return valid; } let temp = target.split(splitter); if (temp.length < index) { return valid; } let result = parseInt(temp[index]); return result; } static readJson(filename: string): any { let file = path.join(__dirname, filename); let data = fs.readFileSync(file); let result: any = SKDataUtil.jsonBy(data.toString()); return result; } // JSON解析 static jsonBy(value: any): any { if (value == null) { return null; } if (!this.isString(value)) { return value; } if (this.isEmptyString(value)) { return null; } let result: any = null; try { result = JSON.parse(value); } catch (error) { SKLogger.warn(`JSON解析:${value},失败:${error}`); } finally { return result; } } // 转换成JSON字符串 static toJson(value: any, valid: string): string { if (value == null) { return valid; } if (this.isString(value)) { return value; } let result: string = valid; try { result = JSON.stringify(value); } catch (error) { SKLogger.warn(`JSON转换:${value},失败:${error}`); } finally { return result; } } // 是否为数字 static isNumber(value: any): boolean { if (value == null) { return false; } let type = typeof value; if (type !== 'number') { return false; } return true; } // 转换成数字 static numberBy(value: any, valid: number = NaN): number { if (this.isNumber(value)) { return value; } if (value == "undefined") { return valid; } if (this.isString(value)) { let result = parseFloat(value); return result; } return valid; } // 转换成字符串 static stringBy(value: any): string { if (value == null) { return ""; } if (this.isString(value)) { return value; } let result = `${value}`; return result; } // 中字符串超长作固定长度加省略号(...)处理 static beautySub(str: any, len: number) { var reg = /[\u4e00-\u9fa5]/g, //专业匹配中文 slice = str.substring(0, len), chineseCharNum = (~~(slice.match(reg) && slice.match(reg).length)), realen = slice.length * 2 - chineseCharNum; return str.substr(0, realen) + (realen < str.length ? "..." : ""); } // 数组去重 static unique(quan_lst: any) { //去掉重复选取的数据 for (let i = 0; i < quan_lst.length; i++) { for (let j = i + 1; j < quan_lst.length;) { if (quan_lst[i][0] == quan_lst[j][0]) { quan_lst.splice(j, 1);//去除重复的对象; } else { j++; } } } return quan_lst; } // sort方法根据数组中对象的某一个属性值进行排序 static compare(property: any){ return function(a: any, b: any){ let value_one = a[property]; let value_two = b[property]; return value_one - value_two; } } // 版本号比较 static checkVersion(versionA: string, versionB: string): number { let vA = versionA.split('.'); let vB = versionB.split('.'); for (let i = 0; i < vA.length; ++i) { let a = parseInt(vA[i]); let b = parseInt(vB[i] || '0'); if (a === b) { continue; } else { return a - b; } } if (vB.length > vA.length) { return -1; } return 0; } // 是否为数组 static isArray(value: any): boolean { if (value == null) { return false; } let result = Array.isArray(value); return result; } // 是否为对象 static isObject(value: any): boolean { if (value == null) { return false; } let type = typeof value; if (type === "object") { return true; } return false; } // 是否为字符串 static isString(value: any): boolean { let result = typeof (value); if (result == "string") { return true; } return false; } // 判断对象是否为空 static isEmptyObject(value: any): boolean { let keys = Object.keys(value); if (keys.length < 1) { return true; } return false; } // 是否为空字符串 static isEmptyString(value: any): boolean { if (value == null) { return true; } if (!this.isString(value)) { return true; } let result = value; if (result.length < 1) { return true; } return false; } // 是否为空数组 static isEmptyArray(value: any): boolean { if (value == null) { return true; } if (!this.isArray(value)) { return true; } let result = value; if (result.length < 1) { return true; } return false; } /** * 判断点与圆心之间的距离和圆半径的关系 * @param pointX 圆的中心点 X * @param pointY 圆的中心点 Y * @param circleX 判断位置的中心点 X * @param circleY 判断位置的中心点 Y * @param radius 半径 */ static confineTo(pointX: number, pointY: number, circleX: number, circleY: number, radius: number): boolean { let dist: number = Math.hypot((pointX - circleX), (pointY - circleY)); let range: number = radius; if (dist > range) { return false; } else if (dist < range) { return true; } else { return false; } } /** * 在一定范围随机生成经纬度 * @param MinLon 最小经度 * @param MaxLon 最大经度 * @param MinLat 最小纬度 * @param MaxLat 最大纬度 */ static randomLonLat(MinLon: number, MaxLon: number, MinLat: number, MaxLat: number): any{ let lon: number = Math.floor(Math.random() * (MaxLon - MinLon) + MinLon); let lat: number = Math.floor(Math.random() * (MaxLat - MinLat) + MinLat); let site: any = [lon,lat]; return site; } // 正则测试 static testRegExp(value: string, regexp: RegExp, min: number, max: number, tip: string) { if (value.length < min) { return `长度不能少于${min}个`; } if (value.length > max) { return `最多只能${max}个`; } let temp = regexp.test(value); if (!temp) { return tip; } return ""; } // 获得键值 static valueForKey(target: any, key: any): any { if (!target) { console.warn(`$警告:获得键值,对象不存在`); return null; } if (key == null) { console.warn(`$警告:获得键值,对象${target}KEY值不存在`); return null; } if (this.isArray(target)) { return target[key]; } if (!this.isObject(target)) { console.warn(`$警告:获得键值,${target}[${key}]不是一个对象`); return null; } let temp: any = target; if (!temp.hasOwnProperty(key)) { return null; } return temp[key]; } // 检查是否合法 static checkValid(value: string): string { if (value == null || value.length < 1) { return "不能为空!"; } let temp = value.trim(); if (value.length != temp.length) { return "两侧不能有空格"; } let list = [{ char: "\"", text: "双引号" }, { char: "\'", text: "单引号" }]; for (let item of list) { if (value.indexOf(item.char) != -1) { return `不能包含${item.text}`; } } return ""; } // 检查MYSQL转义 static checkMYSQL(value: string): string { if (value == null) { return ""; } value.replace(/g\'/g, "\'"); value.replace(/g\"/g, "\""); return value; } static trim(value: string): string { if (value == null || value.length < 1) { return ""; } value = value.trim(); return value; } // 获得最大值经验值 static maxExp(config: any, exp: number): any { let result = exp; for (let key in config) { let item = config[key]; if (exp < item.exp) { result = item.exp; break; } } return result; } // 获得当前阶段的经验值与最大值 static currentExp(config: any, exp: number): any { let result: any = { value: 0, max: 0 }; for (let key in config) { let item = config[key]; let level = item.id; let max_exp = item.exp; if (exp < max_exp) { if (level > 1) { let prev = config[`${level - 1}`]; result.value = exp - prev.exp; result.max = max_exp - prev.exp; } else { result.value = exp; result.max = max_exp; } break; } } return result; } // 是否有属性 static hasProperty(target: any, key: string | number | symbol): boolean { if (target == null) { return false; } if (!this.isObject(target)) { return false; } let result = target; if (result.hasOwnProperty(key)) { return true; } return false; } // 获得字典长度 static getLength(value: any): number { if (value == null) { return 0; } if (Array.isArray(value)) { return value.length; } let length = 0; for (let _key in value) { length++; } return length; } // 对键求和 static getKeyTotal(value: any): number { let total: number = 0; for (let key in value) { let count = parseInt(key); total += count; } return total; } // 深度拷贝 static clone(value: any): any { if (value == null) { return null; } let result: any = Array.isArray(value) ? [] : {}; try { result = SKDataUtil.jsonBy(SKDataUtil.toJson(value, null)); } catch (error) { let info = `警告:深拷贝对象:${value},失败:${error}` console.warn(info); } finally { return result; } } // 克隆类实例 static cloneClass(value: any): any { if (value == null) { return null; } let result = Object.create( Object.getPrototypeOf(value), Object.getOwnPropertyDescriptors(value) ); return result; } // 是否在范围内 static atRange(target: number, range: number[]): boolean { if (this.isEmptyArray(range)) { return false; } for (let item of range) { if (target == item) { return true; } } return false; } // 是否在范围内 static atRangeByString(target: string, keys: string[]): boolean { for (let key of keys) { if (target == key) { return true; } } return false; } static clamp(value: number, min: number, max: number): number { if (value < min) { return min; } if (value > max) { return max; } return value; } // 去除重复 static removeRepeat(list: any[], key: string): any[] { if (list == null || !this.isArray(list) || list.length < 1) { return []; } let filters = []; let result: any[] = []; for (let i = 0; i < list.length; i++) { let item = list[i] let value = item[key]; if (value) { if (filters.indexOf(value) == -1) { filters.push(value); } else { list.splice(i, 1); i--; result.push(item); } } } return result; } // 获得数组元素 static getItemBy(list: any[], index: number): any { if (!this.isArray(list)) { return null; } if (index < 0 || index >= list.length) { return null; } let result = list[index]; return result; } // 保留2位小数 static toDecimal2(value: number): number { let temp = this.numberBy(value); if (isNaN(temp)) { return 0; } temp = Math.round(value * 100) / 100; return temp; } // 从字典中随机抽取一项 static randomDict(value: any[]): any { if (value == null) { return null; } let length = this.getLength(value); if (length < 1) { return null; } let index = this.random(0, length - 1); let data = this.dataOfDictByIndex(value, index); return data; } // 获得字典第几个数据 static dataOfDictByIndex(dict: any, index: number): any { if (index < 0 || index >= SKDataUtil.getLength(dict)) { return null; } let count = -1; for (let key in dict) { count++; if (count == index) { return dict[key]; } } return null; } // 获得定义值 static getDefault(value: any, valid: any): any { if (typeof value == "undefined") return valid; return value; } // 转换Long到53位安全数字 static fixedLong(data: any): any { let type = typeof data; if (type === "object") { for (let key in data) { let value = data[key]; let type = value.constructor.name; if (type === "object") { data[key] = this.fixedLong(value); continue; } if (type === "array") { let index = 0; for (let item of value) { value[index] = this.fixedLong(item); index++; } } if (type === "Long") { let temp = value.toNumber(); if (!Number.isSafeInteger(temp)) { temp = Number.MAX_SAFE_INTEGER; } data[key] = temp; continue; } } } return data; } //阿拉伯数字转中文数字 static noToChinese(num: any) { if (!/^\d*(\.\d*)?$/.test(num)) { alert("Number is wrong!"); return "Number is wrong!"; } let AA = new Array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九"); let BB = new Array("", "十", "百", "千", "万", "亿", "点", ""); let a: any = ("" + num).replace(/(^0*)/g, "").split("."), k: any = 0, re: any = ""; for (let i = a[0].length - 1; i >= 0; i--) { switch (k) { case 0: re = BB[7] + re; break; case 4: if (!new RegExp("0{4}\\d{" + (a[0].length - i - 1) + "}$").test(a[0])) re = BB[4] + re; break; case 8: re = BB[5] + re; BB[7] = BB[5]; k = 0; break; } if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0) re = AA[0] + re; if (a[0].charAt(i) != 0) re = AA[a[0].charAt(i)] + BB[k % 4] + re; k++; } if (a.length > 1) //加上小数部分(如果有小数部分) { re += BB[6]; for (let i = 0; i < a[1].length; i++) re += AA[a[1].charAt(i)]; } return re; } static filter(text: any) { // 红色 蓝色 绿色 分数 紫色 let list: any = [ {reg: new RegExp('#R'),color: ``}, {reg: new RegExp('#L'),color: ``}, {reg: new RegExp('#G'),color: ``}, {reg: new RegExp('#P'),color: ``}, {reg: new RegExp('#V'),color: ``} ]; for (let i = 0; i < list.length; i++) { text = text.replace(list[i].reg, list[i].color);//替换HTML标签$& } if (text.split("").length > 1){ text = text.slice(5) + "" } return text; }; }