923 lines
27 KiB
TypeScript
923 lines
27 KiB
TypeScript
|
/**
|
|||
|
* 数据工具类
|
|||
|
* @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 = <string>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 = <any[]>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 = <Object>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 = <Object>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: `</c ><color=#ff0000 >`},
|
|||
|
{reg: new RegExp('#L'),color: `</c ><color=#0000ff >`},
|
|||
|
{reg: new RegExp('#G'),color: `</c ><color=#228b22 >`},
|
|||
|
{reg: new RegExp('#P'),color: `</c ><color=#ff00ff >`},
|
|||
|
{reg: new RegExp('#V'),color: `</c ><color=#8a2be2 >`}
|
|||
|
];
|
|||
|
for (let i = 0; i < list.length; i++) {
|
|||
|
text = text.replace(list[i].reg, list[i].color);//替换HTML标签$&
|
|||
|
}
|
|||
|
if (text.split("</c >").length > 1){
|
|||
|
text = text.slice(5) + "</c >"
|
|||
|
}
|
|||
|
return text;
|
|||
|
|
|||
|
};
|
|||
|
}
|