first commit

This commit is contained in:
qwq
2026-07-24 11:34:38 +08:00
commit 94f4f174f4
26 changed files with 2544 additions and 0 deletions
+47
View File
@@ -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 };
+17
View File
@@ -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 };
+45
View File
@@ -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;
+15
View File
@@ -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 };