0, 'msg' => 'ok']); exit; } session_start(); $expire = 1800; if (empty($_SESSION['user_id']) || (time() - $_SESSION['login_time'] > $expire)) { echo json_encode(['code' => 401, 'msg' => '登录失效']); exit; } $loginUid = $_SESSION['user_id']; // 工单业务库 monitor $dbWorkHost = '10.150.117.190'; $dbWorkUser = 'root'; $dbWorkPwd = 'hp93000'; $dbWorkName = 'monitor'; $connWork = mysqli_connect($dbWorkHost, $dbWorkUser, $dbWorkPwd, $dbWorkName); if (!$connWork) { echo json_encode(['code' => 500, 'msg' => '工单数据库连接失败:' . mysqli_connect_error()]); exit; } mysqli_set_charset($connWork, 'utf8mb4'); // 配置库 alert_mail_stat(告警、通知配置统一此处) $dbConfHost = "10.150.117.190"; $dbConfUser = "root"; $dbConfPwd = "hp93000"; $dbConfName = "alert_mail_stat"; $connConf = mysqli_connect($dbConfHost, $dbConfUser, $dbConfPwd, $dbConfName); if(!$connConf){ echo json_encode(['code' => 500, 'msg' => '配置库连接失败']); exit; } mysqli_set_charset($connConf, "utf8mb4"); // 获取当前用户角色权限 $isAdmin = 0; $permList = ""; $roleSql = "SELECT r.is_admin, r.perm_list FROM sys_user u LEFT JOIN sys_role r ON u.role_id=r.id WHERE u.uid = ?"; $stmtRole = mysqli_prepare($connWork, $roleSql); mysqli_stmt_bind_param($stmtRole, 's', $loginUid); mysqli_stmt_execute($stmtRole); $roleRes = mysqli_stmt_get_result($stmtRole); $roleRow = $roleRes ? mysqli_fetch_assoc($roleRes) : []; if ($roleRow) { $isAdmin = intval($roleRow['is_admin']); $permList = $roleRow['perm_list']; } $action = $_REQUEST['action'] ?? ''; $post = json_decode(file_get_contents("php://input"), true) ?: []; // ===================== 新增1:根据告警ID查询关联工单 ===================== if ($action === "get_workorder_by_alertid") { $alertId = trim($_GET['alert_id'] ?? ''); if (empty($alertId)) { echo json_encode(['code' => 400, 'msg' => '缺少告警ID参数']); exit; } $alertEsc = mysqli_real_escape_string($connWork, $alertId); $sql = "SELECT id,title,status,assign_uid,create_time FROM work_order WHERE relate_alert_id = ? ORDER BY create_time DESC"; $stmt = mysqli_prepare($connWork, $sql); mysqli_stmt_bind_param($stmt, 's', $alertEsc); mysqli_stmt_execute($stmt); $res = mysqli_stmt_get_result($stmt); $list = []; while ($row = mysqli_fetch_assoc($res)) { $list[] = $row; } echo json_encode(['code' => 0, 'list' => $list]); exit; } // ===================== 新增2:自动同步告警状态,批量更新工单为已完成 ===================== if ($action === "auto_sync_workorder_status") { // 1. 查询所有已恢复的告警(alert_type=2),去重获取告警ID $resolveSql = "SELECT DISTINCT CONCAT(alert_name,'_',instance) as alert_id FROM alert_log WHERE alert_type=2"; $resolveRes = mysqli_query($connConf, $resolveSql); $resolveAlertIds = []; while ($row = mysqli_fetch_assoc($resolveRes)) { $resolveAlertIds[] = $row['alert_id']; } if (empty($resolveAlertIds)) { echo json_encode(['code' => 0, 'msg' => '暂无已恢复告警,无需更新工单', 'update_count' => 0]); exit; } // 2. 拼接IN条件,查询未完成、关联该告警的工单 $inStr = implode("','", array_map(function($v) use ($connWork) { return mysqli_real_escape_string($connWork, $v); }, $resolveAlertIds)); // status=1待处理 / status=2处理中,统一改为3已完成 $updateSql = "UPDATE work_order SET status=3,update_time=NOW() WHERE relate_alert_id IN ('$inStr') AND status IN (1,2)"; mysqli_query($connWork, $updateSql); $updateCnt = mysqli_affected_rows($connWork); echo json_encode([ 'code' => 0, 'msg' => '工单状态自动同步完成,已恢复告警绑定工单全部置为已完成', 'update_count' => $updateCnt ], JSON_UNESCAPED_UNICODE); exit; } // 1、获取实时活跃告警(alert_mail_stat.alert_firing 数据源) if ($action === "get_firing_alert") { $alertSql = "SELECT alert_id,alert_name,instance FROM alert_firing WHERE status='firing' ORDER BY receive_time DESC LIMIT 100"; $res = mysqli_query($connConf, $alertSql); $list = []; if($res instanceof mysqli_result){ while ($row = mysqli_fetch_assoc($res)) { $list[] = $row; } } echo json_encode(['code' => 0, 'list' => $list]); exit; } // 2、新建工单(关联告警、多渠道通知 + 自动判断告警是否已恢复) if ($action === "create") { $title = trim($post['title'] ?? ''); $content = trim($post['content'] ?? ''); $assign = trim($post['assign_uid'] ?? ''); $relateAlertId = trim($post['relate_alert_id'] ?? ''); $notifyUser = trim($post['notify_user'] ?? ''); $notifyChannel = trim($post['notify_channel'] ?? ''); // 默认待处理1;若关联告警已恢复,直接置完成3 $status = 1; if (!$title || !$content) { echo json_encode(['code' => 400, 'msg' => '标题和内容不能为空']); exit; } // 关联了告警,判断该告警是否存在恢复记录 if (!empty($relateAlertId)) { $alertEsc = mysqli_real_escape_string($connConf, $relateAlertId); $checkResolveSql = "SELECT 1 FROM alert_log WHERE CONCAT(alert_name,'_',instance) = ? AND alert_type=2 LIMIT 1"; $stmtCheck = mysqli_prepare($connConf, $checkResolveSql); mysqli_stmt_bind_param($stmtCheck, 's', $alertEsc); mysqli_stmt_execute($stmtCheck); $checkRes = mysqli_stmt_get_result($stmtCheck); if (mysqli_num_rows($checkRes) > 0) { $status = 3; } } $sql = "INSERT INTO work_order(title,content,create_uid,assign_uid,relate_alert_id,notify_user,notify_channel,status,create_time,update_time) VALUES (?,?,?,?,?,?,?,?,NOW(),NOW())"; $stmt = mysqli_prepare($connWork, $sql); mysqli_stmt_bind_param($stmt, 'sssssssi', $title, $content, $loginUid, $assign, $relateAlertId, $notifyUser, $notifyChannel, $status); $ok = mysqli_stmt_execute($stmt); if (!$ok) { echo json_encode(['code' => 500, 'msg' => '创建失败:' . mysqli_error($connWork)]); exit; } $orderId = mysqli_insert_id($connWork); sendWorkOrderNotify($connConf, $connWork, $orderId, $notifyUser, $notifyChannel); echo json_encode(['code' => 0, 'msg' => '工单提交成功,通知已下发', 'init_status' => $status]); exit; } // 3、编辑工单 if ($action === "edit") { $id = intval($post['id'] ?? 0); $title = trim($post['title'] ?? ''); $content = trim($post['content'] ?? ''); $assign = trim($post['assign_uid'] ?? ''); $notifyUser = trim($post['notify_user'] ?? ''); $notifyChannel = trim($post['notify_channel'] ?? ''); if ($id <= 0 || empty($title) || empty($content)) { echo json_encode(['code' => 400, 'msg' => '参数不能为空']); exit; } // 非管理员权限校验 if ($isAdmin !== 1) { $chkSql = "SELECT id FROM work_order WHERE id=? AND (create_uid=? OR assign_uid=?)"; $stmtChk = mysqli_prepare($connWork, $chkSql); mysqli_stmt_bind_param($stmtChk, 'iss', $id, $loginUid, $loginUid); mysqli_stmt_execute($stmtChk); $chkRes = mysqli_stmt_get_result($stmtChk); if (mysqli_num_rows($chkRes) === 0) { echo json_encode(['code' => 403, 'msg' => '无权限编辑该工单']); exit; } } $sql = "UPDATE work_order SET title=?,content=?,assign_uid=?,notify_user=?,notify_channel=?,update_time=NOW() WHERE id=?"; $stmt = mysqli_prepare($connWork, $sql); mysqli_stmt_bind_param($stmt, 'sssssi', $title, $content, $assign, $notifyUser, $notifyChannel, $id); mysqli_stmt_execute($stmt); sendWorkOrderNotify($connConf, $connWork, $id, $notifyUser, $notifyChannel); echo json_encode(['code' => 0, 'msg' => '工单保存成功,通知已更新下发']); exit; } // 4、修改工单状态 if ($action === "update_status") { $id = intval($post['id'] ?? 0); $status = intval($post['status'] ?? 1); if ($id <= 0) { echo json_encode(['code' => 400, 'msg' => '工单ID错误']); exit; } if ($isAdmin !== 1) { $chkSql = "SELECT id FROM work_order WHERE id=? AND (create_uid=? OR assign_uid=?)"; $stmtChk = mysqli_prepare($connWork, $chkSql); mysqli_stmt_bind_param($stmtChk, 'iss', $id, $loginUid, $loginUid); mysqli_stmt_execute($stmtChk); $chkRes = mysqli_stmt_get_result($stmtChk); if (mysqli_num_rows($chkRes) === 0) { echo json_encode(['code' => 403, 'msg' => '无权限操作该工单']); exit; } } $sql = "UPDATE work_order SET status=?,update_time=NOW() WHERE id=?"; $stmt = mysqli_prepare($connWork, $sql); mysqli_stmt_bind_param($stmt, 'ii', $status, $id); mysqli_stmt_execute($stmt); echo json_encode(['code' => 0, 'msg' => '状态更新成功']); exit; } // 5、管理员分发工单(前端统一action=assign,废弃assign_order) if ($action === "assign") { if ($isAdmin !== 1) { echo json_encode(['code' => 403, 'msg' => '仅管理员可分发工单']); exit; } $id = intval($post['id'] ?? 0); $assignUid = trim($post['assign_uid'] ?? ''); $sql = "UPDATE work_order SET assign_uid=?,update_time=NOW() WHERE id=?"; $stmt = mysqli_prepare($connWork, $sql); mysqli_stmt_bind_param($stmt, 'si', $assignUid, $id); mysqli_stmt_execute($stmt); echo json_encode(['code' => 0, 'msg' => '工单分发成功']); exit; } // 新增:同步Prometheus实时告警,自动清理恢复告警(完全独立,无需index.php) if ($action === "sync_prom_alerts") { header("Content-Type: application/json;charset=utf-8"); $promUrl = "http://10.150.117.190:9090/api/v1/alerts"; $resp = @file_get_contents($promUrl); if($resp === false){ echo json_encode(["code"=>500,"msg"=>"无法连接Prometheus接口"],JSON_UNESCAPED_UNICODE); exit; } $promData = json_decode($resp,true); if(!isset($promData['data']['alerts'])){ echo json_encode(["code"=>500,"msg"=>"Prometheus返回数据异常"],JSON_UNESCAPED_UNICODE); exit; } // 1. 先将表内所有告警标记为已恢复 mysqli_query($connConf,"UPDATE alert_firing SET status='resolved'"); // 2. 遍历当前Prometheus活跃告警,写入/更新 $alerts = $promData['data']['alerts'] ?? []; foreach($alerts as $item){ $alertName = $item['labels']['alertname'] ?? "unknown"; $instance = $item['labels']['instance'] ?? "unknown"; $alertId = $alertName."_".$instance; $sql = "INSERT INTO alert_firing(alert_id,alert_name,instance,status,receive_time) VALUES (?,?,?,'firing',NOW()) ON DUPLICATE KEY UPDATE status='firing',receive_time=NOW()"; $stmt = mysqli_prepare($connConf,$sql); mysqli_stmt_bind_param($stmt,"sss",$alertId,$alertName,$instance); mysqli_stmt_execute($stmt); } $syncNum = count($alerts); // 同步完成后自动执行工单状态更新,无需额外调用 $syncWorkUrl = apiOrder . "?action=auto_sync_workorder_status"; @file_get_contents($syncWorkUrl); echo json_encode([ "code"=>0, "msg"=>"Prometheus告警同步完成,已自动同步工单状态", "active_alert_total"=>$syncNum ],JSON_UNESCAPED_UNICODE); exit; } // 定时同步:告警恢复自动完工单 if($_POST['action'] === "sync_alert_auto_close"){ // 1、拉取仪表盘实时未恢复告警 $alertApi = "./index.php?act=active_firing"; $raw = file_get_contents($alertApi); $activeList = json_decode($raw, true) ?: []; $activeKeys = []; foreach($activeList as $item){ $activeKeys[] = $item['alert_name'] . "|" . $item['instance']; } // 2、查询所有未完成、绑定告警的工单 $sql = "SELECT id, relate_alert_id FROM work_order WHERE status IN(1,2) AND relate_alert_id <> ''"; $res = mysqli_query($conn, $sql); while($row = mysqli_fetch_assoc($res)){ // 工单关联告警不在当前活跃列表=已恢复,自动设为完成 if(!in_array($row['relate_alert_id'], $activeKeys)){ $updateSql = "UPDATE work_order SET status=3, update_time=NOW() WHERE id = ".(int)$row['id']; mysqli_query($conn, $updateSql); } } echo json_encode(['code'=>0, 'msg'=>'同步完成']); exit; } // 读取通知配置 $notifyRow = mysqli_fetch_assoc(mysqli_query($conn, "SELECT * FROM sys_workorder_notify LIMIT 1")); if(!$notifyRow || $notifyRow['notify_open'] != 1) return; // 组装钉钉、企业微信请求,curl发送webhook // ==================== 全局通知统一函数 ==================== function sendWorkOrderNotify($connConf, $connWork, $orderId, $notifyUserStr, $channelStr) { if (empty($notifyUserStr) || empty($channelStr)) return; $userArr = explode(",", $notifyUserStr); $channelArr = explode(",", $channelStr); // 读取完整通知配置(邮箱+钉钉+企微) $cfgRes = mysqli_query($connConf, "SELECT * FROM sys_smtp_config WHERE id=1"); $notifyCfg = $cfgRes ? mysqli_fetch_assoc($cfgRes) : []; if(empty($notifyCfg)) return; // 获取工单完整信息 $orderRes = mysqli_query($connWork, "SELECT * FROM work_order WHERE id=$orderId"); $order = $orderRes ? mysqli_fetch_assoc($orderRes) : []; $title = $order['title']; $content = $order['content']; $relateId = $order['relate_alert_id'] ?: "无"; $msgText = "【运维工单通知】\n工单ID:$orderId\n关联告警:$relateId\n标题:$title\n详情:$content"; foreach ($channelArr as $ch) { $ch = trim($ch); switch ($ch) { case "mail": sendMailNotify($notifyCfg, $userArr, $title, $content, $relateId, $orderId); break; case "dingtalk": sendDingNotify($notifyCfg, $msgText); break; case "wecom": sendWecomNotify($notifyCfg, $msgText); break; } } } // 邮件发送 function sendMailNotify($smtp, $uidList, $title, $content, $relateId, $orderId) { if (empty($smtp['smtp_host']) || empty($smtp['smtp_account'])) return; $emailList = []; foreach ($uidList as $uid) { $uid = trim($uid); if (empty($uid)) continue; $res = mysqli_query($GLOBALS['connWork'], "SELECT email FROM sys_user WHERE uid='$uid'"); $u = mysqli_fetch_assoc($res); if (!empty($u['email'])) $emailList[] = $u['email']; } if (empty($emailList)) return; $to = implode(",", array_unique($emailList)); $subject = "【工单通知】#$orderId $title"; $body = "

工单 #$orderId

关联告警ID:$relateId

标题:$title

$content
"; // 此处接入PHPMailer发送逻辑 } // 钉钉机器人推送 function sendDingNotify($cfg, $text) { $webhook = $cfg['ding_webhook'] ?? ''; $secret = $cfg['ding_secret'] ?? ''; if(empty($webhook)) return; $data = json_encode([ "msgtype" => "text", "text" => ["content" => $text] ]); $opts = ["http" => ["method" => "POST", "header" => "Content-Type:application/json", "content" => $data]]; file_get_contents($webhook, false, stream_context_create($opts)); } // 企业微信机器人推送 function sendWecomNotify($cfg, $text) { $webhook = $cfg['wecom_webhook'] ?? ''; if(empty($webhook)) return; $data = json_encode([ "msgtype" => "text", "text" => ["content" => $text] ]); $opts = ["http" => ["method" => "POST", "header" => "Content-Type:application/json", "content" => $data]]; file_get_contents($webhook, false, stream_context_create($opts)); } // 无匹配动作 echo json_encode(['code' => 400, 'msg' => '无效请求动作']); mysqli_close($connWork); mysqli_close($connConf); exit; ?>