205 lines
5.1 KiB
JavaScript
205 lines
5.1 KiB
JavaScript
// 超时提醒系统·reminder.js
|
||
// HoloLake·M-DINGTALK Phase 3
|
||
// DEV-004 之之×秋秋
|
||
//
|
||
// 规则:广播签发后72小时未交SYSLOG → 自动提醒
|
||
//
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
// 数据文件路径(复用Phase 2的多维表格数据)
|
||
const DATA_DIR = path.join(__dirname, '..', 'data');
|
||
const DEVELOPER_TABLE = path.join(DATA_DIR, 'developer-status.json');
|
||
const REMINDER_LOG = path.join(DATA_DIR, 'reminder-log.json');
|
||
|
||
// 提醒配置
|
||
const TIMEOUT_HOURS = 72;
|
||
const REMINDER_INTERVAL_MS = 60 * 60 * 1000; // 每小时检查一次
|
||
|
||
let reminderTimer = null;
|
||
|
||
/**
|
||
* 扫描所有开发者,找出超时未交SYSLOG的
|
||
*/
|
||
function scanOverdue() {
|
||
console.log(`[Reminder] 扫描超时开发者... ${new Date().toLocaleString('zh-CN')}`);
|
||
|
||
// 读取开发者状态表
|
||
if (!fs.existsSync(DEVELOPER_TABLE)) {
|
||
console.log('[Reminder] 开发者状态表不存在,跳过');
|
||
return [];
|
||
}
|
||
|
||
let devTable;
|
||
try {
|
||
devTable = JSON.parse(fs.readFileSync(DEVELOPER_TABLE, 'utf-8'));
|
||
} catch (err) {
|
||
console.error('[Reminder] 读取开发者状态表失败:', err.message);
|
||
return [];
|
||
}
|
||
|
||
const now = Date.now();
|
||
const overdueList = [];
|
||
|
||
for (const dev of (devTable.developers || [])) {
|
||
// 跳过未启动或已完成的开发者
|
||
if (!dev.last_broadcast_time || dev.status === '已完成' || dev.status === '未启动') {
|
||
continue;
|
||
}
|
||
|
||
const broadcastTime = new Date(dev.last_broadcast_time).getTime();
|
||
const hoursSince = (now - broadcastTime) / (1000 * 60 * 60);
|
||
|
||
if (hoursSince >= TIMEOUT_HOURS && dev.status !== 'HOLD') {
|
||
overdueList.push({
|
||
dev_id: dev.dev_id,
|
||
name: dev.name,
|
||
current_module: dev.current_module,
|
||
last_broadcast: dev.last_broadcast_time,
|
||
hours_overdue: Math.round(hoursSince - TIMEOUT_HOURS),
|
||
total_hours: Math.round(hoursSince)
|
||
});
|
||
}
|
||
}
|
||
|
||
if (overdueList.length > 0) {
|
||
console.log(`[Reminder] ⚠️ 发现 ${overdueList.length} 个超时开发者:`);
|
||
for (const dev of overdueList) {
|
||
console.log(` · ${dev.dev_id} ${dev.name} - 超时${dev.hours_overdue}小时 - ${dev.current_module}`);
|
||
}
|
||
} else {
|
||
console.log('[Reminder] 无超时开发者');
|
||
}
|
||
|
||
return overdueList;
|
||
}
|
||
|
||
/**
|
||
* 生成提醒消息(钉钉消息卡片格式)
|
||
*/
|
||
function generateReminderMessage(devInfo) {
|
||
return {
|
||
msgtype: 'markdown',
|
||
markdown: {
|
||
title: `SYSLOG提醒·${devInfo.dev_id}`,
|
||
text: [
|
||
'## ⏰ SYSLOG超时提醒',
|
||
`**${devInfo.name}**(${devInfo.dev_id})`,
|
||
`你的广播已经签发 **${devInfo.total_hours}** 小时了`,
|
||
`超过72小时启动窗口 **${devInfo.hours_overdue}** 小时`,
|
||
`当前任务:${devInfo.current_module}`,
|
||
'**请尽快提交SYSLOG!**',
|
||
'---',
|
||
'✅ 已完成 → 提交完整SYSLOG',
|
||
'❓ 遇到困难 → 截图发群里,秋秋/知秋帮你',
|
||
'⏸️ 暂时没空 → 回复「HOLD」,系统记录',
|
||
'---',
|
||
'🤖 系统自动提醒 · HoloLake'
|
||
].join('\n')
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 执行提醒发送
|
||
*/
|
||
async function executeReminders() {
|
||
const overdueList = scanOverdue();
|
||
if (overdueList.length === 0) return [];
|
||
|
||
const reminderResults = [];
|
||
|
||
for (const dev of overdueList) {
|
||
const message = generateReminderMessage(dev);
|
||
|
||
// 模拟发送(后续接入真实钉钉API)
|
||
console.log(`[Reminder] 向 ${dev.name} 发送提醒消息(模拟)`);
|
||
|
||
reminderResults.push({
|
||
timestamp: new Date().toISOString(),
|
||
dev_id: dev.dev_id,
|
||
hours_overdue: dev.hours_overdue,
|
||
status: 'sent-mock'
|
||
});
|
||
}
|
||
|
||
// 保存提醒日志
|
||
saveReminderLog(reminderResults);
|
||
|
||
return reminderResults;
|
||
}
|
||
|
||
/**
|
||
* 启动定时提醒
|
||
*/
|
||
function start() {
|
||
if (reminderTimer) {
|
||
console.log('[Reminder] 提醒系统已在运行');
|
||
return;
|
||
}
|
||
|
||
console.log(`[Reminder] 启动超时提醒系统 · ${TIMEOUT_HOURS}小时超时 · 每小时扫描一次`);
|
||
|
||
// 启动时立即扫描一次
|
||
executeReminders();
|
||
|
||
// 定时扫描
|
||
reminderTimer = setInterval(executeReminders, REMINDER_INTERVAL_MS);
|
||
|
||
console.log('[Reminder] 定时器已启动');
|
||
}
|
||
|
||
/**
|
||
* 停止定时提醒
|
||
*/
|
||
function stop() {
|
||
if (reminderTimer) {
|
||
clearInterval(reminderTimer);
|
||
reminderTimer = null;
|
||
console.log('[Reminder] 提醒系统已停止');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 保存提醒日志
|
||
*/
|
||
function saveReminderLog(results) {
|
||
if (!fs.existsSync(DATA_DIR)) {
|
||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||
}
|
||
|
||
let log = [];
|
||
if (fs.existsSync(REMINDER_LOG)) {
|
||
try {
|
||
log = JSON.parse(fs.readFileSync(REMINDER_LOG, 'utf-8'));
|
||
} catch {}
|
||
}
|
||
|
||
log.unshift(...results);
|
||
if (log.length > 200) log = log.slice(0, 200);
|
||
|
||
fs.writeFileSync(REMINDER_LOG, JSON.stringify(log, null, 2), 'utf-8');
|
||
}
|
||
|
||
/**
|
||
* 获取提醒系统状态
|
||
*/
|
||
function getStatus() {
|
||
return {
|
||
running: reminderTimer !== null,
|
||
timeoutHours: TIMEOUT_HOURS,
|
||
checkIntervalMinutes: REMINDER_INTERVAL_MS / 60000,
|
||
overdueNow: scanOverdue()
|
||
};
|
||
}
|
||
|
||
module.exports = {
|
||
scanOverdue,
|
||
generateReminderMessage,
|
||
executeReminders,
|
||
start,
|
||
stop,
|
||
getStatus
|
||
};
|