chore: src/comm/utils.ts

This commit is contained in:
2026-07-01 17:55:37 +08:00
parent 0dc79cc011
commit b459a092f3
+271
View File
@@ -0,0 +1,271 @@
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
import * as moment from 'moment';
import * as path from 'path';
/**
* 帮助类
*/
@Provide()
@Scope(ScopeEnum.Singleton)
export class Utils {
@Inject()
baseDir;
/**
* 获得dist路径
*/
getDistPath() {
const runPath = __dirname;
const distIndex =
runPath.lastIndexOf('/dist/') !== -1
? runPath.lastIndexOf('/dist/')
: runPath.lastIndexOf('\\dist\\');
if (distIndex !== -1) {
return path.join(runPath.substring(0, distIndex), 'dist');
}
return path.join(runPath, 'dist');
}
/**
* 获得请求IP
*/
async getReqIP(ctx: Context) {
const req = ctx.req;
return (
req.headers['x-forwarded-for'] ||
req.socket.remoteAddress?.replace('::ffff:', '') ||
''
);
}
/**
* 去除对象的空值属性
* @param obj
*/
async removeEmptyP(obj) {
Object.keys(obj).forEach(key => {
if (obj[key] === null || obj[key] === '' || obj[key] === 'undefined') {
delete obj[key];
}
});
}
/**
* 线程阻塞毫秒数
* @param ms
*/
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* 获得最近几天的日期集合
* @param recently
*/
getRecentlyDates(recently, format = 'YYYY-MM-DD') {
moment.locale('zh-cn');
const dates = [];
for (let i = 0; i < recently; i++) {
dates.push(moment().subtract(i, 'days').format(format));
}
return dates.reverse();
}
/**
* 获得最近几个月的月数
* @param recently
*/
getRecentlyMonths(recently, format = 'YYYY-MM') {
moment.locale('zh-cn');
const dates = [];
const date = moment(Date.now()).format('YYYY-MM');
for (let i = 0; i < recently; i++) {
dates.push(moment(date).subtract(i, 'months').format(format));
}
return dates.reverse();
}
/**
* 根据开始和结束时间,获得时间段内的日期集合
* @param start
* @param end
*/
getBetweenDays(start, end, format = 'YYYY-MM-DD') {
moment.locale('zh-cn');
const dates = [];
const startTime = moment(start).format(format);
const endTime = moment(end).format(format);
const days = moment(endTime).diff(moment(startTime), 'days');
for (let i = 0; i <= days; i++) {
dates.push(moment(startTime).add(i, 'days').format(format));
}
return dates;
}
/**
* 根据开始和结束时间,获得时间段内的月份集合
* @param start
* @param end
*/
getBetweenMonths(start, end, format = 'YYYY-MM') {
moment.locale('zh-cn');
const dates = [];
const startTime = moment(start).format(format);
const endTime = moment(end).format(format);
const months = moment(endTime).diff(moment(startTime), 'months');
for (let i = 0; i <= months; i++) {
dates.push(moment(startTime).add(i, 'months').format(format));
}
return dates;
}
/**
* 根据开始和结束时间,获得时间段内的小时集合
* @param start
* @param end
*/
getBetweenHours(start, end, format = 'YYYY-MM-DD HH') {
moment.locale('zh-cn');
const dates = [];
const startTime = moment(start).format(format);
const endTime = moment(end).format(format);
const hours = moment(endTime).diff(moment(startTime), 'hours');
for (let i = 0; i <= hours; i++) {
dates.push(moment(startTime).add(i, 'hours').format(format));
}
return dates;
}
/**
* 字段转驼峰法
* @param obj
* @returns
*/
toCamelCase(obj) {
const camelCaseObject = {};
for (const i in obj) {
const camelCase = i.replace(/([-_][a-z])/gi, $1 => {
return $1.toUpperCase().replace('-', '').replace('_', '');
});
camelCaseObject[camelCase] = obj[i];
}
return camelCaseObject;
}
/**
* 匹配URL
* @param pattern
* @param url
* @returns
*/
matchUrl(pattern, url) {
// 将 pattern 和 url 按 `/` 分割
const patternParts = pattern.split('/').filter(Boolean);
const urlParts = url.split('/').filter(Boolean);
// 如果长度不匹配且 pattern 不包含 **,直接返回 false
if (patternParts.length !== urlParts.length && !pattern.includes('**')) {
return false;
}
for (let i = 0; i < patternParts.length; i++) {
const patternPart = patternParts[i];
const urlPart = urlParts[i];
// 如果 patternPart 是 **,匹配剩余的所有部分
if (patternPart === '**') {
return true;
}
// 如果 patternPart 以 : 开头,说明是参数,直接匹配任意非空值
if (patternPart.startsWith(':')) {
if (!urlPart) {
return false;
}
continue;
}
// 如果 patternPart 是 *,匹配任意非空部分
if (patternPart === '*') {
if (!urlPart) {
return false;
}
} else if (patternPart !== urlPart) {
return false;
}
}
// 如果 pattern 和 url 的部分数量一致,则匹配成功
return patternParts.length === urlParts.length;
}
/**
* 从文本中提取 JSON 字符串并转换为对象
* @param {string} text - 可能包含 JSON 的文本
* @returns {Object|Array|null} - 解析出的 JSON 对象,如果没有找到有效 JSON 则返回 null
*/
extractJSONFromText(text) {
if (!text || typeof text !== 'string') {
return null;
}
try {
// 尝试直接解析整个文本
return JSON.parse(text);
} catch (e) {
// 整个文本不是有效的 JSON,尝试提取 JSON 部分
}
// 查找可能的 JSON 开始位置({ 或 [)
const possibleStarts = [];
for (let i = 0; i < text.length; i++) {
if (text[i] === '{' || text[i] === '[') {
possibleStarts.push(i);
}
}
// 从每个可能的起始位置尝试提取 JSON
for (const startIndex of possibleStarts) {
let openBraces = 0;
let openBrackets = 0;
let inString = false;
let escapeNext = false;
for (let i = startIndex; i < text.length; i++) {
const char = text[i];
// 处理转义字符
if (inString && !escapeNext && char === '\\') {
escapeNext = true;
continue;
}
// 处理字符串边界
if (!escapeNext && char === '"') {
inString = !inString;
}
if (!inString) {
// 只在不在字符串内部时才计算括号
if (char === '{') openBraces++;
else if (char === '}') openBraces--;
else if (char === '[') openBrackets++;
else if (char === ']') openBrackets--;
}
escapeNext = false;
// 检查是否找到了完整的 JSON 结构
if (
(openBraces === 0 && text[startIndex] === '{' && char === '}') ||
(openBrackets === 0 && text[startIndex] === '[' && char === ']')
) {
const jsonStr = text.substring(startIndex, i + 1);
try {
const result = JSON.parse(jsonStr);
return result;
} catch (e) {
// 这个候选 JSON 无效,继续尝试下一个
break;
}
}
}
}
return null; // 没有找到有效的 JSON
}
}