mirror of
https://github.com/crystelf/crystelf-core.git
synced 2025-07-04 14:49:19 +00:00
commit
66c82dcb01
62
.idea/codeStyles/Project.xml
generated
Normal file
62
.idea/codeStyles/Project.xml
generated
Normal file
@ -0,0 +1,62 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</JSCodeStyleSettings>
|
||||
<TypeScriptCodeStyleSettings version="0">
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="PREFER_EXPLICIT_TYPES_VARS_FIELDS" value="true" />
|
||||
<option name="PREFER_EXPLICIT_TYPES_FUNCTION_RETURNS" value="true" />
|
||||
<option name="PREFER_EXPLICIT_TYPES_FUNCTION_EXPRESSION_RETURNS" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</TypeScriptCodeStyleSettings>
|
||||
<VueCodeStyleSettings>
|
||||
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
|
||||
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
|
||||
</VueCodeStyleSettings>
|
||||
<codeStyleSettings language="HTML">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="TypeScript">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Vue">
|
||||
<option name="SOFT_MARGINS" value="100" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
8
.idea/prettier.xml
generated
Normal file
8
.idea/prettier.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PrettierConfiguration">
|
||||
<option name="myConfigurationMode" value="MANUAL" />
|
||||
<option name="myRunOnSave" value="true" />
|
||||
<option name="myRunOnReformat" value="true" />
|
||||
</component>
|
||||
</project>
|
14
.idea/webResources.xml
generated
Normal file
14
.idea/webResources.xml
generated
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="WebResourcesPaths">
|
||||
<contentEntries>
|
||||
<entry url="file://$PROJECT_DIR$">
|
||||
<entryData>
|
||||
<resourceRoots>
|
||||
<path value="file://$PROJECT_DIR$/src" />
|
||||
</resourceRoots>
|
||||
</entryData>
|
||||
</entry>
|
||||
</contentEntries>
|
||||
</component>
|
||||
</project>
|
@ -9,7 +9,8 @@
|
||||
"dependencies": {
|
||||
"chalk": "4",
|
||||
"dotenv": "^16.0.0",
|
||||
"express": "^4.18.0"
|
||||
"express": "^4.18.0",
|
||||
"mkdirp": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.0",
|
||||
|
49
src/app.ts
49
src/app.ts
@ -1,23 +1,50 @@
|
||||
import express from 'express';
|
||||
import logger from './utils/logger';
|
||||
import fc from './utils/file';
|
||||
import paths from './utils/path';
|
||||
import logger from './utils/core/logger';
|
||||
import paths from './utils/core/path';
|
||||
import sampleController from './modules/sample/sample.controller';
|
||||
import imageController from './modules/image/image.controller';
|
||||
import Config from './utils/core/config';
|
||||
import fc from './utils/core/file';
|
||||
|
||||
const apps = {
|
||||
createApp() {
|
||||
const app = express();
|
||||
|
||||
logger.info('晶灵核心初始化..');
|
||||
|
||||
Config.check(['PORT', 'DEBUG']);
|
||||
|
||||
app.use(express.json());
|
||||
app.use('/public', express.static(paths.get('public')));
|
||||
logger.debug(`路由/public挂载成功..`);
|
||||
app.use('/api/sample', sampleController.getRouter());
|
||||
logger.debug(`路由/api/sample挂载成功..`);
|
||||
app.use('/images', imageController.getRouter());
|
||||
logger.debug(`路由/images挂载成功..`);
|
||||
fc.createDir(paths.get('log'));
|
||||
logger.info('晶灵核心初始化成功!');
|
||||
logger.debug('成功加载express.json()中间件');
|
||||
|
||||
const publicPath = paths.get('public');
|
||||
app.use('/public', express.static(publicPath));
|
||||
logger.debug(`静态资源路由挂载:/public → ${publicPath}`);
|
||||
|
||||
const modules = [
|
||||
{ path: '/api/sample', name: '测试模块', controller: sampleController },
|
||||
{ path: '/images', name: '图像模块', controller: imageController },
|
||||
];
|
||||
|
||||
modules.forEach((module) => {
|
||||
app.use(module.path, module.controller.getRouter());
|
||||
logger.debug(`模块路由挂载: ${module.path.padEnd(12)} → ${module.name}`);
|
||||
|
||||
if (Config.get('DEBUG', false)) {
|
||||
module.controller.getRouter().stack.forEach((layer) => {
|
||||
if (layer.route) {
|
||||
const methods = Object.keys(layer.route)
|
||||
.map((m) => m.toUpperCase())
|
||||
.join(',');
|
||||
logger.debug(` ↳ ${methods.padEnd(6)} ${module.path}${layer.route.path}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
const logPath = paths.get('log');
|
||||
fc.createDir(logPath);
|
||||
logger.debug(`日志目录初始化: ${logPath}`);
|
||||
logger.info('晶灵核心初始化完毕!');
|
||||
return app;
|
||||
},
|
||||
};
|
||||
|
1
src/config/keep
Normal file
1
src/config/keep
Normal file
@ -0,0 +1 @@
|
||||
keep
|
@ -1,5 +1,5 @@
|
||||
import apps from './app';
|
||||
import logger from './utils/logger';
|
||||
import logger from './utils/core/logger';
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
|
1
src/middlewares/keep
Normal file
1
src/middlewares/keep
Normal file
@ -0,0 +1 @@
|
||||
keep
|
@ -1,6 +1,6 @@
|
||||
import express from 'express';
|
||||
import ImageService from './image.service';
|
||||
import logger from '../../utils/logger';
|
||||
import logger from '../../utils/core/logger';
|
||||
|
||||
class ImageController {
|
||||
private readonly router: express.Router;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import paths from '../../utils/path';
|
||||
import logger from '../../utils/logger';
|
||||
import paths from '../../utils/core/path';
|
||||
import logger from '../../utils/core/logger';
|
||||
|
||||
class ImageService {
|
||||
private readonly imageDir: string;
|
||||
|
1
src/modules/monitor/kep
Normal file
1
src/modules/monitor/kep
Normal file
@ -0,0 +1 @@
|
||||
keep
|
@ -1,5 +1,6 @@
|
||||
import express from 'express';
|
||||
import sampleService from './sample.service';
|
||||
import response from '../../utils/core/response';
|
||||
|
||||
class SampleController {
|
||||
private readonly router: express.Router;
|
||||
@ -21,37 +22,24 @@ class SampleController {
|
||||
private getHello = (req: express.Request, res: express.Response): void => {
|
||||
try {
|
||||
const result = sampleService.getHello();
|
||||
this.sendSuccess(res, result);
|
||||
response.success(res, result);
|
||||
} catch (error) {
|
||||
this.sendError(res, error);
|
||||
response.error(res, '请求失败了..', 500, error);
|
||||
}
|
||||
};
|
||||
|
||||
private postGreet = (req: express.Request, res: express.Response): void => {
|
||||
try {
|
||||
const { name } = req.body;
|
||||
if (!name) {
|
||||
return response.error(res, '姓名不能为空!', 400);
|
||||
}
|
||||
const result = sampleService.generateGreeting(name);
|
||||
this.sendSuccess(res, result);
|
||||
response.success(res, result);
|
||||
} catch (error) {
|
||||
this.sendError(res, error);
|
||||
response.error(res, '请求失败了..', 500, error);
|
||||
}
|
||||
};
|
||||
|
||||
private sendSuccess(res: express.Response, data: any, statusCode = 200): void {
|
||||
res.status(statusCode).json({
|
||||
success: true,
|
||||
data,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
private sendError(res: express.Response, error: any, statusCode = 500): void {
|
||||
res.status(statusCode).json({
|
||||
success: false,
|
||||
message: error.message,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new SampleController();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import logger from '../../utils/logger';
|
||||
import logger from '../../utils/core/logger';
|
||||
|
||||
class SampleService {
|
||||
getHello() {
|
||||
@ -6,7 +6,7 @@ class SampleService {
|
||||
return { message: 'Hello World!' };
|
||||
}
|
||||
|
||||
generateGreeting(name: string) {
|
||||
generateGreeting(name: string): object {
|
||||
logger.debug(`有个小可爱正在请求generateGreeting方法..`);
|
||||
if (!name) {
|
||||
logger.warn('Name is required');
|
||||
|
1
src/modules/trss/keep
Normal file
1
src/modules/trss/keep
Normal file
@ -0,0 +1 @@
|
||||
keep
|
1
src/types/keep
Normal file
1
src/types/keep
Normal file
@ -0,0 +1 @@
|
||||
keep
|
@ -1,23 +0,0 @@
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
let config = {
|
||||
get: (key: string, defaultValue: any) => {
|
||||
const value = process.env[key];
|
||||
if (value === undefined) {
|
||||
if (defaultValue !== undefined) return defaultValue;
|
||||
throw new Error(`环境变量${key}未定义..`);
|
||||
}
|
||||
|
||||
if (typeof defaultValue === 'number') return Number(value);
|
||||
if (typeof defaultValue === 'boolean') return value === 'true';
|
||||
return value;
|
||||
},
|
||||
|
||||
set: (key: string, value: any) => {
|
||||
process.env[key] = value;
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
1
src/utils/constants/keep
Normal file
1
src/utils/constants/keep
Normal file
@ -0,0 +1 @@
|
||||
keep
|
72
src/utils/core/config.ts
Normal file
72
src/utils/core/config.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import dotenv from 'dotenv';
|
||||
import logger from './logger';
|
||||
|
||||
class ConfigManger {
|
||||
private static instance: ConfigManger;
|
||||
private env: NodeJS.ProcessEnv;
|
||||
|
||||
private constructor() {
|
||||
dotenv.config();
|
||||
this.env = process.env;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单例实例
|
||||
*/
|
||||
public static getInstance(): ConfigManger {
|
||||
if (!ConfigManger.instance) {
|
||||
ConfigManger.instance = new ConfigManger();
|
||||
}
|
||||
return ConfigManger.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取环境变量(带类型推断)
|
||||
* @param key 环境变量键名
|
||||
* @param defaultValue 默认值(决定返回类型)
|
||||
*/
|
||||
public get<T = string>(key: string, defaultValue?: T): T {
|
||||
const value = this.env[key];
|
||||
if (value === undefined) {
|
||||
if (defaultValue !== undefined) return defaultValue;
|
||||
logger.error(`环境变量${key}未定义!`);
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
switch (typeof defaultValue) {
|
||||
case 'number':
|
||||
return Number(value) as T;
|
||||
case 'boolean':
|
||||
return (value === 'true') as T;
|
||||
default:
|
||||
return value as T;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置环境变量(运行时有效)
|
||||
* @param key 键名
|
||||
* @param value 值
|
||||
*/
|
||||
public set(key: string, value: string | number | boolean): void {
|
||||
this.env[key] = String(value);
|
||||
logger.debug(`成功更改环境变量${key}为${value}!`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查环境变量是否已加载
|
||||
*/
|
||||
public check(keys: string[]): void {
|
||||
keys.forEach((key) => {
|
||||
if (!(key in this.env)) {
|
||||
logger.error(`必须环境变量缺失:${key}`);
|
||||
} else {
|
||||
logger.debug(`检测到环境变量${key}!`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const Config = ConfigManger.getInstance();
|
||||
|
||||
export default Config;
|
74
src/utils/core/date.ts
Normal file
74
src/utils/core/date.ts
Normal file
@ -0,0 +1,74 @@
|
||||
class date {
|
||||
/**
|
||||
* 获取当前日期 (格式: YYYYMMDD)
|
||||
*/
|
||||
public static getCurrentDate(): string {
|
||||
const now = new Date();
|
||||
return [
|
||||
now.getFullYear(),
|
||||
(now.getMonth() + 1).toString().padStart(2, '0'),
|
||||
now.getDate().toString().padStart(2, '0'),
|
||||
].join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间 (格式: HH:mm:ss)
|
||||
*/
|
||||
public static getCurrentTime(): string {
|
||||
return new Date().toLocaleTimeString('en-US', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取格式化日期时间
|
||||
* @param formatStr 格式字符串 (YYYY-年, MM-月, DD-日, HH-时, mm-分, ss-秒)
|
||||
* @example format('YYYY-MM-DD HH:mm:ss') => '2023-10-15 14:30:45'
|
||||
*/
|
||||
public static format(formatStr: string = 'YYYY-MM-DD HH:mm:ss'): string {
|
||||
const now = new Date();
|
||||
|
||||
const replacements: Record<string, string> = {
|
||||
YYYY: now.getFullYear().toString(),
|
||||
MM: (now.getMonth() + 1).toString().padStart(2, '0'),
|
||||
DD: now.getDate().toString().padStart(2, '0'),
|
||||
HH: now.getHours().toString().padStart(2, '0'),
|
||||
mm: now.getMinutes().toString().padStart(2, '0'),
|
||||
ss: now.getSeconds().toString().padStart(2, '0'),
|
||||
};
|
||||
|
||||
return formatStr.replace(/YYYY|MM|DD|HH|mm|ss/g, (match) => replacements[match]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算日期差值
|
||||
* @param start 开始日期
|
||||
* @param end 结束日期 (默认当前时间)
|
||||
* @param unit 返回单位 ('days' | 'hours' | 'minutes' | 'seconds')
|
||||
*/
|
||||
public static diff(
|
||||
start: Date,
|
||||
end: Date = new Date(),
|
||||
unit: 'days' | 'hours' | 'minutes' | 'seconds' = 'days'
|
||||
): number {
|
||||
const msDiff = end.getTime() - start.getTime();
|
||||
|
||||
switch (unit) {
|
||||
case 'seconds':
|
||||
return Math.floor(msDiff / 1000);
|
||||
case 'minutes':
|
||||
return Math.floor(msDiff / (1000 * 60));
|
||||
case 'hours':
|
||||
return Math.floor(msDiff / (1000 * 60 * 60));
|
||||
case 'days':
|
||||
return Math.floor(msDiff / (1000 * 60 * 60 * 24));
|
||||
default:
|
||||
return msDiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default date;
|
@ -1,13 +1,14 @@
|
||||
import path from 'path';
|
||||
import paths from './path';
|
||||
import date from './date';
|
||||
import fs from 'fs';
|
||||
import chalk from 'chalk';
|
||||
import paths from './path';
|
||||
import date from './date';
|
||||
import logger from './logger';
|
||||
|
||||
let fc = {
|
||||
createDir: (targetPath: string = '', includeFile: boolean = false) => {
|
||||
class fc {
|
||||
public static createDir(targetPath: string = '', includeFile: boolean = false): void {
|
||||
const root = paths.get('root');
|
||||
|
||||
if (path.isAbsolute(targetPath)) {
|
||||
if (includeFile) {
|
||||
const parentDir = path.dirname(targetPath);
|
||||
@ -17,6 +18,7 @@ let fc = {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(targetPath)) {
|
||||
fs.mkdirSync(targetPath, { recursive: true });
|
||||
logger.debug(`成功创建绝对目录: ${targetPath}`);
|
||||
@ -27,20 +29,21 @@ let fc = {
|
||||
const fullPath = includeFile
|
||||
? path.join(root, path.dirname(targetPath))
|
||||
: path.join(root, targetPath);
|
||||
|
||||
if (!fs.existsSync(fullPath)) {
|
||||
fs.mkdirSync(fullPath, { recursive: true });
|
||||
logger.debug(`成功创建相对目录: ${fullPath}`);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
logToFile: (level: string, message: string) => {
|
||||
public static logToFile(level: string, message: string): void {
|
||||
const logFile = path.join(paths.get('log'), `${date.getCurrentDate()}.log`);
|
||||
const logMessage = `[${date.getCurrentTime()}] [${level}] ${message}\n`;
|
||||
|
||||
fs.appendFile(logFile, logMessage, (err) => {
|
||||
if (err) console.error(chalk.red('[LOGGER] 写入日志失败:'), err);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default fc;
|
68
src/utils/core/logger.ts
Normal file
68
src/utils/core/logger.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import chalk from 'chalk';
|
||||
import Config from './config';
|
||||
import fc from './file';
|
||||
|
||||
class Logger {
|
||||
private static instance: Logger;
|
||||
private readonly isDebug: boolean;
|
||||
|
||||
private constructor() {
|
||||
this.isDebug = Config.get('DEBUG', false);
|
||||
}
|
||||
|
||||
public static getInstance(): Logger {
|
||||
if (!Logger.instance) {
|
||||
Logger.instance = new Logger();
|
||||
}
|
||||
return Logger.instance;
|
||||
}
|
||||
|
||||
public debug(...args: any[]): void {
|
||||
if (this.isDebug) {
|
||||
const message = this.formatMessage('DEBUG', args);
|
||||
console.log(chalk.cyan(message));
|
||||
}
|
||||
}
|
||||
|
||||
public info(...args: any[]): void {
|
||||
const message = this.formatMessage('INFO', args);
|
||||
console.log(chalk.green(message));
|
||||
this.logToFile('INFO', message);
|
||||
}
|
||||
|
||||
public warn(...args: any[]): void {
|
||||
const message = this.formatMessage('WARN', args);
|
||||
console.log(chalk.yellow(message));
|
||||
this.logToFile('WARN', message);
|
||||
}
|
||||
|
||||
public error(...args: any[]): void {
|
||||
const message = this.formatMessage('ERROR', args);
|
||||
console.error(chalk.red(message));
|
||||
this.logToFile('ERROR', message);
|
||||
}
|
||||
|
||||
public fatal(args: any[], exitCode: number = 1): never {
|
||||
const message = this.formatMessage('FATAL', args);
|
||||
console.error(chalk.red.bold(message));
|
||||
this.logToFile('FATAL', message);
|
||||
process.exit(exitCode);
|
||||
}
|
||||
|
||||
private formatMessage(level: string, args: any[]): string {
|
||||
return `[${level}] ${args
|
||||
.map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : arg))
|
||||
.join(' ')}`;
|
||||
}
|
||||
|
||||
private logToFile(level: string, message: string): void {
|
||||
try {
|
||||
fc.logToFile(level, `${new Date().toISOString()} ${message}`);
|
||||
} catch (err: any) {
|
||||
console.error(chalk.red(`[LOGGER] 写入日志失败: ${err.message}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const logger = Logger.getInstance();
|
||||
export default logger;
|
62
src/utils/core/path.ts
Normal file
62
src/utils/core/path.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
class PathManager {
|
||||
private static instance: PathManager;
|
||||
private readonly baseDir: string;
|
||||
|
||||
private constructor() {
|
||||
this.baseDir = path.join(__dirname, '../..');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单例实例
|
||||
*/
|
||||
public static getInstance(): PathManager {
|
||||
if (!PathManager.instance) {
|
||||
PathManager.instance = new PathManager();
|
||||
}
|
||||
return PathManager.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取预定义路径
|
||||
* @param type 路径类型
|
||||
*/
|
||||
public get(type?: PathType): string {
|
||||
const mappings: Record<PathType, string> = {
|
||||
root: this.baseDir,
|
||||
public: path.join(this.baseDir, 'public'),
|
||||
images: path.join(this.baseDir, 'public/images'),
|
||||
log: path.join(this.baseDir, 'logs'),
|
||||
config: path.join(this.baseDir, 'config'),
|
||||
temp: path.join(this.baseDir, 'temp'),
|
||||
};
|
||||
|
||||
return type ? mappings[type] : this.baseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析相对路径(基于项目根目录)
|
||||
* @param segments 路径片段
|
||||
*/
|
||||
public resolve(...segments: string[]): string {
|
||||
return path.join(this.baseDir, ...segments);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查路径是否存在(同步)
|
||||
*/
|
||||
public existsSync(targetPath: string): boolean {
|
||||
try {
|
||||
return fs.existsSync(targetPath);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type PathType = 'root' | 'public' | 'images' | 'log' | 'config' | 'temp';
|
||||
|
||||
const paths = PathManager.getInstance();
|
||||
export default paths;
|
61
src/utils/core/response.ts
Normal file
61
src/utils/core/response.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { Response } from 'express';
|
||||
import logger from './logger';
|
||||
|
||||
class response {
|
||||
/**
|
||||
* 成功响应
|
||||
* @param res Express响应对象
|
||||
* @param data 返回数据
|
||||
* @param statusCode HTTP状态码,默认200
|
||||
*/
|
||||
static success(res: Response, data: any, statusCode = 200) {
|
||||
res.status(statusCode).json({
|
||||
success: true,
|
||||
data,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应
|
||||
* @param res Express响应对象
|
||||
* @param message 错误信息
|
||||
* @param statusCode HTTP状态码,默认500
|
||||
* @param error 原始错误对象(开发环境显示)
|
||||
*/
|
||||
static error(res: Response, message: string, statusCode = 500, error?: any) {
|
||||
const response: Record<string, any> = {
|
||||
success: false,
|
||||
message,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
logger.debug(error instanceof Error ? error.stack : error);
|
||||
|
||||
res.status(statusCode).json(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页数据响应
|
||||
* @param res Express响应对象
|
||||
* @param data 数据数组
|
||||
* @param total 总条数
|
||||
* @param page 当前页码
|
||||
* @param pageSize 每页条数
|
||||
*/
|
||||
static pagination(res: Response, data: any[], total: number, page: number, pageSize: number) {
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data,
|
||||
pagination: {
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages: Math.ceil(total / pageSize),
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default response;
|
@ -1,11 +0,0 @@
|
||||
let date = {
|
||||
getCurrentDate: () => {
|
||||
const now = new Date();
|
||||
return `${now.getFullYear()}${(now.getMonth() + 1).toString().padStart(2, '0')}${now.getDate().toString().padStart(2, '0')}`;
|
||||
},
|
||||
getCurrentTime: () => {
|
||||
return new Date().toLocaleTimeString('en-US', { hour12: false });
|
||||
},
|
||||
};
|
||||
|
||||
export default date;
|
1
src/utils/helpers/keep
Normal file
1
src/utils/helpers/keep
Normal file
@ -0,0 +1 @@
|
||||
keep
|
0
src/utils/index.ts
Normal file
0
src/utils/index.ts
Normal file
1
src/utils/lib/keep
Normal file
1
src/utils/lib/keep
Normal file
@ -0,0 +1 @@
|
||||
keep
|
@ -1,30 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
import config from './config';
|
||||
import fc from './file';
|
||||
|
||||
const logger = {
|
||||
debug: (...args: any[]) => {
|
||||
if (config.get('DEBUG', false)) {
|
||||
//const message = args.join(' ');
|
||||
console.log(chalk.cyan('[DEBUG]'), ...args);
|
||||
//fc.logToFile('DEBUG', message);
|
||||
}
|
||||
},
|
||||
info: (...args: any[]) => {
|
||||
const message = args.join(' ');
|
||||
console.log(chalk.green('[INFO]'), ...args);
|
||||
fc.logToFile('INFO', message);
|
||||
},
|
||||
warn: (...args: any[]) => {
|
||||
const message = args.join(' ');
|
||||
console.log(chalk.yellow('[WARN]'), ...args);
|
||||
fc.logToFile('WARN', message);
|
||||
},
|
||||
error: (...args: any[]) => {
|
||||
const message = args.join(' ');
|
||||
console.log(chalk.red('[ERROR]'), ...args);
|
||||
fc.logToFile('ERROR', message);
|
||||
},
|
||||
};
|
||||
|
||||
export default logger;
|
@ -1,24 +0,0 @@
|
||||
import path from 'path';
|
||||
|
||||
const paths = {
|
||||
get: (value?: string) => {
|
||||
switch (value) {
|
||||
case 'root':
|
||||
return path.join(__dirname, '..');
|
||||
case 'public':
|
||||
return path.join(__dirname, '../public');
|
||||
case 'images':
|
||||
return path.join(__dirname, '../../public/images/');
|
||||
case 'log':
|
||||
return path.join(__dirname, '../../logs');
|
||||
default:
|
||||
return path.join(__dirname, '..');
|
||||
}
|
||||
},
|
||||
|
||||
resolve: (segments: string) => {
|
||||
return path.join(__dirname, segments);
|
||||
},
|
||||
};
|
||||
|
||||
export default paths;
|
Loading…
x
Reference in New Issue
Block a user