first commit
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
const axios = require('axios');
|
||||
const config = require('../config');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
/**
|
||||
* 通过飞书群机器人 Webhook 发送告警
|
||||
*/
|
||||
async function sendAlert(title, content, level = 'warning') {
|
||||
const webhookUrl = config.feishu.alertWebhook;
|
||||
if (!webhookUrl) {
|
||||
logger.warn('未配置告警 Webhook,跳过告警发送');
|
||||
return;
|
||||
}
|
||||
|
||||
const colorMap = { info: 'blue', warning: 'orange', error: 'red' };
|
||||
|
||||
const card = {
|
||||
msg_type: 'interactive',
|
||||
card: {
|
||||
header: {
|
||||
title: { tag: 'plain_text', content: `[${level.toUpperCase()}] ${title}` },
|
||||
template: colorMap[level] || 'orange',
|
||||
},
|
||||
elements: [
|
||||
{
|
||||
tag: 'div',
|
||||
text: { tag: 'lark_md', content },
|
||||
},
|
||||
{
|
||||
tag: 'note',
|
||||
elements: [
|
||||
{ tag: 'plain_text', content: `文件传输自动化系统 · ${new Date().toLocaleString('zh-CN')}` },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
await axios.post(webhookUrl, card, { timeout: 10000 });
|
||||
logger.info(`告警已发送: ${title}`);
|
||||
} catch (err) {
|
||||
logger.error(`告警发送失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { sendAlert };
|
||||
@@ -0,0 +1,17 @@
|
||||
const dayjs = require('dayjs');
|
||||
|
||||
/**
|
||||
* 获取当天日期字符串,格式 YYYYMMDD
|
||||
*/
|
||||
function getTodayStr() {
|
||||
return dayjs().format('YYYYMMDD');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间字符串
|
||||
*/
|
||||
function nowStr() {
|
||||
return dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
|
||||
module.exports = { getTodayStr, nowStr };
|
||||
@@ -0,0 +1,45 @@
|
||||
const winston = require('winston');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const LOG_DIR = path.join(__dirname, '..', 'data', 'logs');
|
||||
if (!fs.existsSync(LOG_DIR)) {
|
||||
fs.mkdirSync(LOG_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.json()
|
||||
),
|
||||
defaultMeta: { service: 'file-transfer-automation' },
|
||||
transports: [
|
||||
// 所有日志
|
||||
new winston.transports.File({
|
||||
filename: path.join(LOG_DIR, 'combined.log'),
|
||||
maxsize: 10 * 1024 * 1024, // 10MB
|
||||
maxFiles: 10,
|
||||
}),
|
||||
// 错误日志单独一份
|
||||
new winston.transports.File({
|
||||
filename: path.join(LOG_DIR, 'error.log'),
|
||||
level: 'error',
|
||||
maxsize: 10 * 1024 * 1024,
|
||||
maxFiles: 5,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// 开发环境输出到控制台
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
logger.add(new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.simple()
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
module.exports = logger;
|
||||
@@ -0,0 +1,15 @@
|
||||
const { pinyin } = require('pinyin-pro');
|
||||
|
||||
/**
|
||||
* 将中文姓名转为拼音(小写、无声调、无空格)
|
||||
* 例: "张三" -> "zhangsan"
|
||||
*/
|
||||
function nameToPinyin(name) {
|
||||
if (!name) return '';
|
||||
return pinyin(name, { toneType: 'none', type: 'array' })
|
||||
.join('')
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z]/g, '');
|
||||
}
|
||||
|
||||
module.exports = { nameToPinyin };
|
||||
Reference in New Issue
Block a user