|
|
/** url地址相关工具 */
|
|
|
export const url = {
|
|
|
/**
|
|
|
* 将对象转换为url参数形式,支持忽略指定字段
|
|
|
* @param obj { x: 1, y: 2, z: 3 }
|
|
|
* @param ignoreFields ['z']
|
|
|
* @returns x=1&y=2
|
|
|
*/
|
|
|
objToUrlParma: (obj: Record<string, any>, ignoreFields: Array<string> = []): string => {
|
|
|
return (
|
|
|
'?' +
|
|
|
Object.keys(obj)
|
|
|
.filter((key) => ignoreFields.indexOf(key) === -1)
|
|
|
.map((key) => `${key}=${obj[key]}`)
|
|
|
.join('&')
|
|
|
);
|
|
|
},
|
|
|
/**
|
|
|
* 获取url参数对象
|
|
|
* @param url {string} 完整url,默认当前页面url
|
|
|
* @returns {Record<string, any>} { x: 1, y: 2, z: 3 }
|
|
|
*/
|
|
|
getUrlToParams: (url: string = window.location.href): Record<string, any> => {
|
|
|
/**
|
|
|
* 匹配?与#之间的字符串,即url后面的参数
|
|
|
* 例1: http://127.0.0.1:8080/?x=1&y=2#/index
|
|
|
* 例2: http://127.0.0.1:8080/#/index?x=1&y=2
|
|
|
* 匹配上面两种格式的url参数(主要是#号位置不同导致的判断不同)
|
|
|
*/
|
|
|
const match = url.match(/\?(.+?)(?:#|$)/);
|
|
|
const urlParams = new URLSearchParams(match ? match[1] : '');
|
|
|
const params = {};
|
|
|
for (const [key, value] of urlParams.entries()) {
|
|
|
params[key] = value;
|
|
|
}
|
|
|
return params;
|
|
|
},
|
|
|
};
|
|
|
|
|
|
/** route路由相关工具 */
|
|
|
export const route = {
|
|
|
FILE_NAME_PREFIX: '/src/views',
|
|
|
convertPathToName: (path: string): string => {
|
|
|
return path
|
|
|
.split('/') // 分割路径
|
|
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1)) // 首字母大写
|
|
|
.join(''); // 连接成字符串
|
|
|
},
|
|
|
getTitleFromPathStr: (arr: any, path: string, ignoreFields: string = ''): string => {
|
|
|
const item = arr.find(({ key }) => path.includes(key));
|
|
|
return item ? item.title : path.replace(ignoreFields, ''); // 如果找到,返回 title;否则返回文件名
|
|
|
},
|
|
|
getRankFromPathStr: (arr: any, path: string, ignoreFields: string = ''): string => {
|
|
|
const item = arr.find(({ key }) => path.includes(key));
|
|
|
return item && item.rank ? item.rank : 99; // 如果找到,返回 title;否则返回99
|
|
|
},
|
|
|
mergeDuplicatePathSegments(path: string) {
|
|
|
// 移除开头和结尾的斜杠,然后按斜杠分割
|
|
|
const segments = path.replace(/^\/|\/$/g, '').split('/');
|
|
|
|
|
|
// 如果最后两个段相同且至少有2个段
|
|
|
if (segments.length >= 2 && segments[segments.length - 1] === segments[segments.length - 2]) {
|
|
|
// 移除最后一个段
|
|
|
segments.pop();
|
|
|
// 重新组合路径
|
|
|
return '/' + segments.join('/');
|
|
|
}
|
|
|
|
|
|
// 不需要处理的情况,返回原路径
|
|
|
return path;
|
|
|
},
|
|
|
};
|
|
|
|
|
|
/** 数组相关工具 */
|
|
|
export const array = {
|
|
|
/**
|
|
|
* 判断两个数组是否相等,只递归一层,如果有嵌套数组或对象,则只判断第一层,并且永远不相等
|
|
|
* 支持忽略指定字段
|
|
|
* [{ a:1, b:2 }, { c:3, d:4 }] 比较 [{ a:1, b:2 }, { c:3, d:4 }] 结果为 true
|
|
|
* [{ a:1, b:2 }, { c:3, d:4 }] 比较 [{ a:1, b:2 }, { c:3, d:5 }] 结果为 false
|
|
|
* [{ a:1, b: { b1: 1 }}, { c:3, d:4 }] 比较 [{ a:1, b: { b1: 1 }}, { c:3, d:4 }] 结果为false,因为b是对象,只比较第一层
|
|
|
* @param arr1
|
|
|
* @param arr2
|
|
|
* @param ignoreFields ['a', 'b']
|
|
|
* @returns boolean
|
|
|
*/
|
|
|
arraysAreEqual: (arr1: any[], arr2: any[], ignoreFields: Array<string> = []): boolean => {
|
|
|
if (arr1.length !== arr2.length) {
|
|
|
return false;
|
|
|
}
|
|
|
return arr1.every((item, index) => {
|
|
|
const item2 = arr2[index];
|
|
|
if (typeof item === 'object' && typeof item2 === 'object') {
|
|
|
return Object.keys(item)
|
|
|
.filter((key) => ignoreFields.indexOf(key) === -1)
|
|
|
.every((key) => item[key] === item2[key]);
|
|
|
} else {
|
|
|
return item === item2;
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
};
|
|
|
|
|
|
/** date相关工具 */
|
|
|
export const date = {
|
|
|
/**
|
|
|
* 获取本地时间的ISO字符串
|
|
|
* @param date {string | Date} 日期字符串或Date对象
|
|
|
* @returns {string} 本地时间的ISO字符串 '2022-01-01T08:00:00.000Z'
|
|
|
* @example
|
|
|
* getLocalISOString('2022-01-01 00:00:00') // '2022-01-01T00:00:00.000Z'
|
|
|
* getLocalISOString(new Date('2022-01-01 00:00:00')) // '2022-01-01T00:00:00.000Z'
|
|
|
*/
|
|
|
getLocalISOString: (date: string | Date): string => {
|
|
|
const localDate = new Date(date);
|
|
|
// 获取本地时间偏移量(这里特指中国utc+8)
|
|
|
const offset = localDate.getTimezoneOffset() * 60000;
|
|
|
// 获取utc的本地时间
|
|
|
const utcDate = new Date(localDate.getTime() - offset);
|
|
|
return utcDate.toISOString();
|
|
|
},
|
|
|
};
|
|
|
|
|
|
/** 判断字符串不能为指定的特殊字符 */
|
|
|
export const isSpecialChar = (str: string, specialChars?: string): boolean => {
|
|
|
if (!specialChars) {
|
|
|
specialChars = `~~!!@#$¥%^&*()_+-={}[]【】|\\:;"''""“”<>《》,,.。??/;;…`;
|
|
|
}
|
|
|
const specialCharsArr = specialChars.split('');
|
|
|
return specialCharsArr.some((char) => str.includes(char));
|
|
|
};
|
|
|
|
|
|
export const generateUUID = () => {
|
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
|
const r = (Math.random() * 16) | 0,
|
|
|
v = c == 'x' ? r : (r & 0x3) | 0x8;
|
|
|
return v.toString(16);
|
|
|
});
|
|
|
};
|
|
|
|
|
|
/** 获取远程资源markdown内的内容 */
|
|
|
export const getMarkdownContent = (filePath) => {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
fetch(filePath, {
|
|
|
method: 'GET',
|
|
|
})
|
|
|
.then((result) => {
|
|
|
result
|
|
|
.text()
|
|
|
.then((res) => {
|
|
|
resolve(res);
|
|
|
})
|
|
|
.catch((err) => reject(err));
|
|
|
})
|
|
|
.catch((err) => reject(err));
|
|
|
});
|
|
|
};
|