Files
aler_dashboard_git/alert_dashboard/www/work_order.php.3.0
T
2026-07-07 13:29:22 +08:00

958 lines
35 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
session_start();
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Pragma: no-cache");
header("Expires: Thu, 01 Jan 1970 00:00:00 GMT");
$expire = 1800;
if (empty($_SESSION['user_id']) || (time() - $_SESSION['login_time'] > $expire)) {
session_destroy();
header("Location: login.php");
exit;
}
$_SESSION['login_time'] = time();
$userName = htmlspecialchars($_SESSION['username']);
$userRole = $_SESSION['role'];
$roleText = $userRole === 'admin' ? '管理员' : '只读用户';
// 读取全局配置库
$dbHost = "10.150.117.190";
$dbUser = "root";
$dbPwd = "hp93000";
$dbName = "alert_mail_stat";
$connConfig = mysqli_connect($dbHost, $dbUser, $dbPwd, $dbName);
mysqli_set_charset($connConfig, "utf8mb4");
$configSql = "SELECT k,v FROM sys_config";
$configRes = mysqli_query($connConfig, $configSql);
$sysConfig = [];
while ($row = mysqli_fetch_assoc($configRes)) {
$sysConfig[$row['k']] = $row['v'];
}
mysqli_close($connConfig);
$pageTitle = htmlspecialchars($sysConfig['page_title'] ?? "告警监控系统");
$themeColor = htmlspecialchars($sysConfig['theme_color'] ?? "#409eff");
$pageSize = $sysConfig['page_size'] ?? "20";
$footerText = htmlspecialchars($sysConfig['footer_text'] ?? "");
$sidebarRawLinks = $sysConfig['sidebar_links'] ?? "";
$currentLang = $sysConfig['lang'] ?? "zh";
// 多语言词典
$langMap = [
'zh' => [
'html_lang' => 'zh-CN',
'page_subtitle' => '爱德万测试 · 运维告警监控平台',
'monitor_panel' => '监控面板',
'alert_overview' => '告警监控总览',
'disk_capacity' => '服务器磁盘容量',
'alert_list_page' => '历史告警查询',
'quick_link' => '快捷外链',
'system_manage' => '系统管理',
'system_config' => '后台配置管理',
'current_user' => '当前用户:',
'sys_time' => '系统时间:',
'refresh_all' => '刷新全部数据',
'export_csv' => '导出CSV',
'logout' => '退出登录',
'lang_text' => '语言:',
'work_order_mgr' => '工单系统',
'work_order_title' => '工单管理',
'work_create' => '新建工单',
'work_edit' => '编辑工单',
'work_assign' => '分发工单',
'work_status' => '工单状态',
'work_creator' => '创建人',
'work_handler' => '处理人',
'work_content' => '工单内容/备注',
'work_title' => '工单标题',
'work_create_time' => '创建时间',
'work_update_time' => '更新时间',
'work_all_list' => '全部工单列表',
'work_no_data' => '暂无工单记录',
'work_save' => '保存',
'work_cancel' => '取消',
'work_placeholder_title' => '填写故障/需求标题',
'work_placeholder_content' => '详细描述故障、操作步骤、处理备注',
'work_select_handler' => '选择处理人(留空暂不分配)',
'status_1' => '待处理',
'status_2' => '处理中',
'status_3' => '已完成',
'status_4' => '已关闭',
'no_alert_choose' => '不关联任何告警',
'relate_alert' => '关联告警(可选)',
'relate_alert_id' => '关联告警ID'
],
'en' => [
'html_lang' => 'en',
'page_subtitle' => 'Advantest · O&M Alert Monitor Platform',
'monitor_panel' => 'Monitor Panel',
'alert_overview' => 'Alert Overview',
'disk_capacity' => 'Server Disk Capacity',
'alert_list_page' => 'Alert Pagination List',
'quick_link' => 'Quick Links',
'system_manage' => 'System Manage',
'system_config' => 'System Config',
'current_user' => 'User: ',
'sys_time' => 'System Time: ',
'refresh_all' => 'Refresh All Data',
'export_csv' => 'Export CSV',
'logout' => 'Logout',
'lang_text' => 'Lang: ',
'work_order_mgr' => 'Work Order System',
'work_order_title' => 'Work Order Manage',
'work_create' => 'Create Order',
'work_edit' => 'Edit Order',
'work_assign' => 'Assign Order',
'work_status' => 'Status',
'work_creator' => 'Creator',
'work_handler' => 'Handler',
'work_content' => 'Content / Remark',
'work_title' => 'Order Title',
'work_create_time' => 'Create Time',
'work_update_time' => 'Update Time',
'work_all_list' => 'All Work Order List',
'work_no_data' => 'No order data',
'work_save' => 'Save',
'work_cancel' => 'Cancel',
'work_placeholder_title' => 'Fill fault or demand title',
'work_placeholder_content' => 'Describe fault, steps and handling remark',
'work_select_handler' => 'Select handler (empty for unassigned)',
'status_1' => 'Pending',
'status_2' => 'Processing',
'status_3' => 'Finished',
'status_4' => 'Closed',
'no_alert_choose' => 'No related alert',
'relate_alert' => 'Relate Alert (Optional)',
'relate_alert_id' => 'Relate Alert ID'
]
];
$t = $langMap[$currentLang];
// 解析外链菜单
$sidebarLinkList = [];
if (!empty($sidebarRawLinks)) {
$lines = explode("\n", $sidebarRawLinks);
foreach ($lines as $line) {
$line = trim($line);
if (empty($line)) continue;
$item = explode("|", $line, 2);
if (count($item) === 2) {
$sidebarLinkList[] = [
"name" => trim($item[0]),
"url" => trim($item[1])
];
}
}
}
// ========== 工单业务库 monitor ==========
$dbWorkHost = "10.150.117.190";
$dbWorkUser = "root";
$dbWorkPwd = "hp93000";
$dbWorkName = "monitor";
$connWork = mysqli_connect($dbWorkHost, $dbWorkUser, $dbWorkPwd, $dbWorkName);
if (!$connWork) die("Work DB connect fail: " . mysqli_connect_error());
mysqli_set_charset($connWork, "utf8mb4");
$loginUid = $_SESSION['user_id'];
// 获取当前用户是否管理员
$isAdmin = 0;
$roleSql = "SELECT r.is_admin 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);
$roleRow = mysqli_fetch_assoc(mysqli_stmt_get_result($stmtRole));
if ($roleRow) $isAdmin = intval($roleRow['is_admin']);
// 用户下拉
$userOptions = "";
$userRes = mysqli_query($connWork, "SELECT uid, real_name, username FROM sys_user WHERE enable = 1");
while ($u = mysqli_fetch_assoc($userRes)) {
$userOptions .= '<option value="' . $u['uid'] . '">' . $u['real_name'] . '(' . $u['username'] . ')</option>';
}
// 读取活跃告警下拉(关联工单)
$alertConn = mysqli_connect("10.150.117.190","root","hp93000","alert_mail_stat",3306);
$alertOptions = '<option value="">-- '.$t['no_alert_choose'].' --</option>';
if($alertConn){
mysqli_set_charset($alertConn,"utf8mb4");
$alertSql = "SELECT alert_id,alert_name,instance FROM alert_firing ORDER BY receive_time DESC LIMIT 100";
$alertRes = mysqli_query($alertConn,$alertSql);
while($row = mysqli_fetch_assoc($alertRes)){
$aid = htmlspecialchars($row['alert_id']);
$aname = htmlspecialchars($row['alert_name']);
$ip = htmlspecialchars($row['instance']);
$alertOptions .= "<option value=\"$aid\" data-name=\"$aname\" data-ip=\"$ip\">[$aid] $aname | $ip</option>";
}
mysqli_close($alertConn);
}
// 分页【修复非数字、除零警告】
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$pageSize = intval($sysConfig['page_size'] ?? 20);
if ($pageSize < 1) $pageSize = 20;
$offset = ($page - 1) * $pageSize;
// 权限过滤
if ($isAdmin === 1) {
$whereSql = " 1=1 ";
} else {
$whereSql = " (create_uid = ? OR assign_uid = ?) ";
}
// 统计总数
$cntSql = "SELECT COUNT(*) total FROM work_order WHERE " . $whereSql;
$stmtCnt = mysqli_prepare($connWork, $cntSql);
if ($isAdmin !== 1) {
mysqli_stmt_bind_param($stmtCnt, 'ss', $loginUid, $loginUid);
}
mysqli_stmt_execute($stmtCnt);
$cntRow = mysqli_fetch_assoc(mysqli_stmt_get_result($stmtCnt));
$total = intval($cntRow['total'] ?? 0);
// 防除零
if ($pageSize <= 0) {
$totalPage = 1;
} else {
$totalPage = ceil($total / $pageSize);
}
// 工单列表查询(带关联告警ID
$listSql = "SELECT wo.*, uc.real_name create_name, ua.real_name assign_name
FROM work_order wo
LEFT JOIN sys_user uc ON wo.create_uid = uc.uid
LEFT JOIN sys_user ua ON wo.assign_uid = ua.uid
WHERE " . $whereSql . " ORDER BY create_time DESC LIMIT ?, ?";
$stmtList = mysqli_prepare($connWork, $listSql);
if ($isAdmin === 1) {
mysqli_stmt_bind_param($stmtList, 'ii', $offset, $pageSize);
} else {
mysqli_stmt_bind_param($stmtList, 'ssii', $loginUid, $loginUid, $offset, $pageSize);
}
mysqli_stmt_execute($stmtList);
$listResult = mysqli_stmt_get_result($stmtList);
$orderList = [];
while ($row = mysqli_fetch_assoc($listResult)) {
$orderList[] = $row;
}
mysqli_close($connWork);
?>
<!DOCTYPE html>
<html lang="<?php echo $t['html_lang']; ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo $pageTitle; ?> - Advantest <?php echo $t['work_order_mgr']; ?></title>
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
<script src="/static/js/echarts.min.js"></script>
<script src="/static/js/jquery.min.js"></script>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{
background:#f9fafc;
font-family:"Inter","PingFang SC","Microsoft YaHei";
color:#1d2939;
line-height:1.6;
display:flex;
flex-direction:column;
height:100vh;
overflow:hidden;
}
.wrap-main{
display:flex;
flex:1;
overflow:hidden;
}
.sidebar{
width:240px;
background:#152c5b;
color:#e2e8f0;
flex-shrink:0;
overflow-y:auto;
}
.sidebar-brand{
padding:26px 24px;
border-bottom:1px solid rgba(255,255,255,0.1);
}
.sidebar-brand-en{
font-size:20px;
font-weight:700;
letter-spacing:1px;
color:#fff;
}
.sidebar-brand-cn{
font-size:13px;
color:#a5b4fc;
margin-top:4px;
}
.sidebar-menu{
padding:16px 0;
}
.menu-title{
padding:10px 24px;
font-size:12px;
color:#94a3b8;
letter-spacing:1px;
}
.menu-item{
display:flex;
align-items:center;
gap:12px;
padding:14px 24px;
cursor:pointer;
font-size:14px;
transition:0.2s;
color:#cbd5e1;
}
.menu-item i{
font-size:16px;
width:20px;
text-align:center;
}
.menu-item.active{
background:rgba(255,255,255,0.12);
color:#fff;
border-left:4px solid #3b82f6;
}
.menu-item:hover:not(.active){
background:rgba(255,255,255,0.06);
color:#fff;
}
.main-content{
flex:1;
overflow-y:auto;
display:flex;
flex-direction:column;
}
.header{
background:#ffffff;
border-bottom:1px solid #eef2fb;
color:#152c5b;
padding:20px 40px;
display:flex;
justify-content:space-between;
align-items:center;
box-shadow:0 2px 12px rgba(21,44,91,0.05);
flex-shrink:0;
}
.header-left{
display:flex;
align-items:center;
gap:14px;
}
.header-brand-en{
font-size:24px;
font-weight:700;
letter-spacing:2px;
color:#152c5b;
}
.header-brand-cn{
font-size:15px;
color:#64748b;
}
.header-right{
display:flex;
align-items:center;
gap:18px;
font-size:14px;
flex-wrap:wrap;
}
.user-info,.time-info,.lang-box{
color:#475569;
display:flex;
align-items:center;
gap:6px;
}
.lang-box select{
padding:4px 8px;
border:1px solid #cbd5e1;
border-radius:6px;
}
.btn-base{
border:none;
padding:9px 20px;
border-radius:8px;
cursor:pointer;
font-size:14px;
display:flex;
align-items:center;
gap:6px;
transition:all 0.2s ease;
}
.btn-outline{
background:#ffffff;
color:#152c5b;
border:1px solid #cbd5e1;
}
.btn-outline:hover{
background:#f7f8fc;
border-color:#152c5b;
}
.btn-primary{
background:#152c5b;
color:#fff;
}
.btn-primary:hover{
background:#0f1e42;
}
.btn-success{
background:#10b981;
color:#fff;
}
.btn-success:hover{
background:#059669;
}
.mask{
position:fixed;
left:0;top:0;
width:100%;height:100%;
background:rgba(255,255,255,0.85);
display:none;
z-index:999;
align-items:center;
justify-content:center;
}
.mask-box{
background:#fff;
padding:30px 40px;
border-radius:14px;
font-size:15px;
display:flex;
gap:14px;
align-items:center;
box-shadow:0 8px 30px rgba(21,44,91,0.12);
border:1px solid #eef2fb;
}
.loading{
display:inline-block;
width:20px;height:20px;
border:2px solid #e2e8f0;
border-top-color:#152c5b;
border-radius:50%;
animation:spin 0.8s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}
.container{
padding:36px 40px;
max-width:100%;
flex:1;
}
.page-panel{
display:none;
}
.page-panel.active{
display:block;
}
.base-card{
background:#fff;
border-radius:16px;
padding:32px;
box-shadow:0 3px 18px rgba(21,44,91,0.06);
border:1px solid #eef2fb;
margin-bottom:36px;
}
.title-wrap{
display:flex;
justify-content:space-between;
align-items:center;
margin-bottom:26px;
padding-bottom:16px;
border-bottom:1px solid #eef2fb;
}
.title-left{
display:flex;
align-items:center;
gap:12px;
font-size:19px;
font-weight:600;
color:#152c5b;
}
.title-left i{color:#2563eb;font-size:21px}
.table-count{font-size:14px;color:#64748b}
.table-wrap{overflow-x:auto}
table{width:100%;border-collapse:collapse;font-size:14px}
th{
background:#f9fafc;
color:#475569;
font-weight:600;
padding:16px 18px;
text-align:left;
border-bottom:2px solid #e2e8f0;
white-space:nowrap;
}
th i{margin-right:6px;font-size:13px;color:#94a3b8}
td{
padding:18px;
border-bottom:1px solid #f1f5f9;
color:#334155;
}
tbody tr{transition:background 0.2s}
tbody tr:hover{background:#f7f8fc}
tbody tr:nth-child(even){background:#fbfcfe}
.empty-state{
text-align:center;
padding:80px 20px;
color:#94a3b8;
font-size:15px;
}
.empty-icon{
font-size:56px;
margin-bottom:18px;
opacity:0.35;
}
.modal-mask{
position:fixed;top:0;left:0;width:100%;height:100%;
background:rgba(0,0,0,0.4);display:none;align-items:center;justify-content:center;z-index:999;
}
.modal-box{
width:680px;background:#fff;border-radius:16px;padding:32px;
box-shadow:0 8px 30px rgba(21,44,91,0.12);
}
.modal-head{
display:flex;justify-content:space-between;align-items:center;margin-bottom:26px;
padding-bottom:16px;border-bottom:1px solid #eef2fb;
}
.modal-close{cursor:pointer;font-size:22px;color:#94a3b8;}
.form-row{margin-bottom:20px;}
.form-row label{display:block;margin-bottom:8px;color:#475569;font-weight:500;}
.form-row input,.form-row select,.form-row textarea{
width:100%;padding:10px 14px;border:1px solid #cbd5e1;border-radius:8px;font-size:14px;
}
.form-row textarea{height:140px;resize:none;}
.btn-group{display:flex;gap:14px;margin-top:10px;}
.select-sm{
padding:6px 8px;border:1px solid #cbd5e1;border-radius:6px;font-size:13px;
}
.status-tag{
display:inline-flex;
align-items:center;
gap:5px;
padding:6px 14px;
border-radius:24px;
font-size:13px;
font-weight:500;
}
.status-1{background:#ffedd5;color:#ea580c}
.status-2{background:#dbeafe;color:#2563eb}
.status-3{background:#dcfce7;color:#16a34a}
.status-4{background:#f1f5f9;color:#64748b}
.page-pagination{
display:flex;justify-content:space-between;align-items:center;margin-top:20px;
}
.page-pag-btn{
padding:8px 16px;border:1px solid #cbd5e1;background:#fff;border-radius:8px;cursor:pointer;font-size:14px;
}
.page-pag-btn:hover{background:#f7f8fc;border-color:#152c5b;}
@media (max-width:768px){
.wrap-main{flex-direction:column;}
.sidebar{width:100%;height:auto}
.header{padding:16px 24px;flex-direction:column;gap:16px;align-items:flex-start}
.header-right{flex-wrap:wrap}
.container{padding:24px}
.base-card{padding:24px}
}
</style>
</head>
<body>
<div class="mask" id="exportMask">
<div class="mask-box">
<span class="loading"></span>
<span></span>
</div>
</div>
<div class="wrap-main">
<div class="sidebar">
<div class="sidebar-brand">
<div class="sidebar-brand-en">Advantest</div>
<div class="sidebar-brand-cn"><?php echo $t['page_subtitle']; ?></div>
</div>
<div class="sidebar-menu">
<div class="menu-title"><?php echo $t['monitor_panel']; ?></div>
<div class="menu-item" data-page="alertPage" onclick="location.href='dashboard.php'">
<i class="fa fa-line-chart"></i>
<span><?php echo $t['alert_overview']; ?></span>
</div>
<div class="menu-item" data-page="diskPage" onclick="location.href='dashboard.php#diskPage'">
<i class="fa fa-hdd-o"></i>
<span><?php echo $t['disk_capacity']; ?></span>
</div>
<div class="menu-item" onclick="window.open('alert_list.php','_blank')">
<i class="fa fa-list"></i>
<span><?php echo $t['alert_list_page']; ?></span>
</div>
<div class="menu-item active" data-page="workOrderPage">
<i class="fa fa-ticket"></i>
<span><?php echo $t['work_order_mgr']; ?></span>
</div>
<?php if (!empty($sidebarLinkList)): ?>
<div class="menu-title"><?php echo $t['quick_link']; ?></div>
<?php foreach ($sidebarLinkList as $link): ?>
<div class="menu-item" onclick="window.open('<?php echo htmlspecialchars($link['url']); ?>')">
<i class="fa fa-external-link"></i>
<span><?php echo htmlspecialchars($link['name']); ?></span>
</div>
<?php endforeach; ?>
<?php endif; ?>
<div class="menu-title"><?php echo $t['system_manage']; ?></div>
<div class="menu-item" onclick="location.href='admin.php'">
<i class="fa fa-cog"></i>
<span><?php echo $t['system_config']; ?></span>
</div>
</div>
</div>
<div class="main-content">
<div class="header">
<div class="header-left">
<div>
<div class="header-brand-en">Advantest</div>
<div class="header-brand-cn"><?php echo $t['page_subtitle']; ?></div>
</div>
</div>
<div class="header-right">
<span class="user-info"><i class="fa fa-user-circle"></i><?php echo $t['current_user']; ?><?php echo $userName; ?><?php echo $roleText; ?></span>
<span class="time-info"><i class="fa fa-clock-o"></i><?php echo $t['sys_time']; ?><span id="updateTime">--</span></span>
<div class="lang-box">
<span><?php echo $t['lang_text']; ?></span>
<select id="langSwitch">
<option value="zh" <?php echo $currentLang==='zh'?'selected':''; ?>>中文</option>
<option value="en" <?php echo $currentLang==='en'?'selected':''; ?>>EN</option>
</select>
</div>
<button class="btn-base btn-outline" onclick="loadAllData()"><i class="fa fa-refresh"></i><?php echo $t['refresh_all']; ?></button>
<button class="btn-base btn-primary" id="logoutBtn"><i class="fa fa-sign-out"></i><?php echo $t['logout']; ?></button>
</div>
</div>
<div class="container">
<div class="page-panel active" id="workOrderPage">
<div class="base-card">
<div class="title-wrap">
<div class="title-left"><i class="fa fa-ticket"></i><?php echo $t['work_all_list']; ?></div>
<button class="btn-base btn-success" id="openCreateModal"><i class="fa fa-plus"></i><?php echo $t['work_create']; ?></button>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>ID</th>
<th><i class="fa fa-link"></i><?php echo $t['relate_alert_id']; ?></th>
<th><i class="fa fa-file-text"></i><?php echo $t['work_title']; ?></th>
<th><i class="fa fa-user"></i><?php echo $t['work_creator']; ?></th>
<th><i class="fa fa-user-o"></i><?php echo $t['work_handler']; ?></th>
<th><i class="fa fa-tag"></i><?php echo $t['work_status']; ?></th>
<th><i class="fa fa-calendar"></i><?php echo $t['work_create_time']; ?></th>
<th><i class="fa fa-clock-o"></i><?php echo $t['work_update_time']; ?></th>
<th><?php echo $t['work_assign']; ?> / <?php echo $t['work_edit']; ?></th>
</tr>
</thead>
<tbody>
<?php if (count($orderList) === 0): ?>
<tr>
<td colspan="9">
<div class="empty-state">
<div class="empty-icon"><i class="fa fa-ticket"></i></div>
<div><?php echo $t['work_no_data']; ?></div>
</div>
</td>
<?php else: ?>
<?php foreach ($orderList as $item): ?>
<?php
$statusText = '';
$statusClass = '';
switch ($item['status']) {
case 1: $statusText = $t['status_1']; $statusClass = 'status-1'; break;
case 2: $statusText = $t['status_2']; $statusClass = 'status-2'; break;
case 3: $statusText = $t['status_3']; $statusClass = 'status-3'; break;
case 4: $statusText = $t['status_4']; $statusClass = 'status-4'; break;
}
?>
<tr data-id="<?php echo $item['id']; ?>"
data-title="<?php echo htmlspecialchars($item['title']); ?>"
data-content="<?php echo htmlspecialchars($item['content']); ?>"
data-assign="<?php echo $item['assign_uid']; ?>"
data-status="<?php echo $item['status']; ?>"
data-relate="<?php echo htmlspecialchars($item['relate_alert_id'] ?? ''); ?>">
<td><?php echo $item['id']; ?></td>
<td><?php echo htmlspecialchars($item['relate_alert_id'] ?? '-'); ?></td>
<td><?php echo htmlspecialchars($item['title']); ?></td>
<td><?php echo $item['create_name'] ?? '-'; ?></td>
<td><?php echo $item['assign_name'] ?? '-'; ?></td>
<td><span class="status-tag <?php echo $statusClass; ?>"><?php echo $statusText; ?></span></td>
<td><?php echo $item['create_time']; ?></td>
<td><?php echo $item['update_time'] ?? '-'; ?></td>
<td style="display:flex;gap:6px;align-items:center;">
<?php if ($isAdmin === 1): ?>
<select class="assign-user select-sm">
<option value="">--</option>
<?php echo $userOptions; ?>
</select>
<?php endif; ?>
<select class="status-select select-sm">
<option value="1" <?php echo $item['status']==1?'selected':''; ?>><?php echo $t['status_1']; ?></option>
<option value="2" <?php echo $item['status']==2?'selected':''; ?>><?php echo $t['status_2']; ?></option>
<option value="3" <?php echo $item['status']==3?'selected':''; ?>><?php echo $t['status_3']; ?></option>
<option value="4" <?php echo $item['status']==4?'selected':''; ?>><?php echo $t['status_4']; ?></option>
</select>
<button class="btn-base btn-outline btn-sm edit-order"><i class="fa fa-edit"></i></button>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<div class="page-pagination">
<div><?php echo $currentLang==='zh'?'共 ':'Total '; ?><?php echo $total; ?> <?php echo $currentLang==='zh'?'条':'records'; ?></div>
<div style="display:flex;gap:10px;align-items:center;">
<?php if ($page > 1): ?>
<button class="page-pag-btn" onclick="location.href='work_order.php?page=<?php echo $page-1; ?>'"><?php echo $currentLang==='zh'?'上一页':'Prev' ?></button>
<?php endif; ?>
<span><?php echo $currentLang==='zh'?'第':'Page '; ?><?php echo $page; ?> / <?php echo $totalPage; ?></span>
<?php if ($page < $totalPage): ?>
<button class="page-pag-btn" onclick="location.href='work_order.php?page=<?php echo $page+1; ?>'"><?php echo $currentLang==='zh'?'下一页':'Next' ?></button>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 新建工单弹窗(带告警关联下拉) -->
<div class="modal-mask" id="createModal">
<div class="modal-box">
<div class="modal-head">
<h3 class="title-left"><i class="fa fa-plus"></i><?php echo $t['work_create']; ?></h3>
<span class="modal-close" id="closeCreateModal">×</span>
</div>
<div class="form-row">
<label><?php echo $t['relate_alert']; ?></label>
<select id="relateAlertSelect">
<?php echo $alertOptions; ?>
</select>
<div class="form-desc"><?php echo $currentLang==='zh'?'选择后自动填充工单标题与基础告警信息':'Auto fill title & alert info after select'; ?></div>
</div>
<div class="form-row">
<label><?php echo $t['work_title']; ?></label>
<input type="text" id="orderTitle" placeholder="<?php echo $t['work_placeholder_title']; ?>">
</div>
<div class="form-row">
<label><?php echo $t['work_content']; ?></label>
<textarea id="orderContent" placeholder="<?php echo $t['work_placeholder_content']; ?>"></textarea>
</div>
<div class="form-row">
<label><?php echo $t['work_handler']; ?></label>
<select id="orderAssign">
<option value=""><?php echo $t['work_select_handler']; ?></option>
<?php echo $userOptions; ?>
</select>
</div>
<div class="btn-group">
<button class="btn-base btn-primary" id="submitOrder"><i class="fa fa-save"></i><?php echo $t['work_save']; ?></button>
<button class="btn-base btn-outline" id="resetForm"><?php echo $t['work_cancel']; ?></button>
</div>
</div>
</div>
<!-- 编辑工单弹窗(仅展示关联告警,不可修改) -->
<div class="modal-mask" id="editModal">
<div class="modal-box">
<div class="modal-head">
<h3 class="title-left"><i class="fa fa-edit"></i><?php echo $t['work_edit']; ?></h3>
<span class="modal-close" id="closeEditModal">×</span>
</div>
<input type="hidden" id="editOrderId">
<input type="hidden" id="editRelateAlertId">
<div class="form-row">
<label><?php echo $t['relate_alert']; ?></label>
<input type="text" id="editRelateAlertShow" readonly style="background:#f7f8fc;color:#64748b;">
</div>
<div class="form-row">
<label><?php echo $t['work_title']; ?></label>
<input type="text" id="editTitle">
</div>
<div class="form-row">
<label><?php echo $t['work_content']; ?></label>
<textarea id="editContent"></textarea>
</div>
<div class="form-row">
<label><?php echo $t['work_handler']; ?></label>
<select id="editAssign">
<option value="">--</option>
<?php echo $userOptions; ?>
</select>
</div>
<div class="btn-group">
<button class="btn-base btn-primary" id="saveEdit"><i class="fa fa-save"></i><?php echo $t['work_save']; ?></button>
<button class="btn-base btn-outline" id="cancelEdit"><?php echo $t['work_cancel']; ?></button>
</div>
</div>
</div>
<script>
const apiOrder = "./api/work_order_api.php";
const loginUid = "<?php echo $loginUid; ?>";
const isAdmin = <?php echo $isAdmin; ?>;
const currentLang = "<?php echo $currentLang; ?>";
// 语言切换
$("#langSwitch").change(function(){
const newLang = $(this).val();
fetch("./api/index.php",{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded"},
body:"act=save_lang&lang="+newLang
}).then(()=>location.href = "work_order.php?_t="+new Date().getTime());
})
// 选中告警自动回填表单
$("#relateAlertSelect").change(function(){
const opt = $(this).find("option:selected");
const aid = opt.val();
const aname = opt.data("name") || "";
const ip = opt.data("ip") || "";
if(!aid){
$("#orderTitle").val("");
$("#orderContent").val("");
return;
}
const baseText = currentLang === "zh"
? `关联告警ID${aid}\n实例IP${ip}\n告警名称:${aname}\n=====处理备注=====\n`
: `Relate Alert ID: ${aid}\nInstance IP: ${ip}\nAlert Name: ${aname}\n=====Handling Remark=====\n`;
$("#orderTitle").val(aname);
$("#orderContent").val(baseText);
});
// 重置表单
$("#resetForm").click(function(){
$("#relateAlertSelect").val("");
$("#orderTitle").val("");
$("#orderContent").val("");
$("#orderAssign").val("");
});
// 打开编辑弹窗回填数据
$(document).on("click",".edit-order",function(){
const tr = $(this).closest("tr");
$("#editOrderId").val(tr.data("id"));
$("#editTitle").val(tr.data("title"));
$("#editContent").val(tr.data("content"));
$("#editAssign").val(tr.data("assign"));
const relateAid = tr.data("relate") || "";
$("#editRelateAlertId").val(relateAid);
$("#editRelateAlertShow").val(relateAid || (currentLang==="zh"?"无关联告警":"No related alert"));
$("#editModal").css("display","flex");
});
$("#closeEditModal,#cancelEdit").click(()=>$("#editModal").hide());
$("#closeCreateModal").click(()=>$("#createModal").hide());
// 提交新建工单
$("#submitOrder").click(function(){
const title = $("#orderTitle").val().trim();
const content = $("#orderContent").val().trim();
const assign = $("#orderAssign").val();
const relateAlertId = $("#relateAlertSelect").val();
if(!title) return alert(currentLang==='zh'?"请填写工单标题":"Fill order title");
if(!content) return alert(currentLang==='zh'?"请填写工单内容":"Fill order content");
$.ajax({
url: apiOrder + "?action=create",
method: "POST",
contentType: "application/json",
data: JSON.stringify({
title: title,
content: content,
assign_uid: assign,
relate_alert_id: relateAlertId
}),
dataType: "json",
success(res){
alert(res.msg);
if(res.code === 0) location.reload();
},
error(){alert(currentLang==='zh'?"提交失败,接口异常":"Submit failed, API error")}
})
});
// 保存编辑工单
$("#saveEdit").click(function(){
const id = $("#editOrderId").val();
const title = $("#editTitle").val().trim();
const content = $("#editContent").val().trim();
const assign = $("#editAssign").val();
if(!title || !content) return alert(currentLang==='zh'?"标题和内容不能为空":"Title and content required");
$.ajax({
url: apiOrder + "?action=edit",
method: "POST",
contentType: "application/json",
data: JSON.stringify({id,title,content,assign_uid:assign}),
dataType: "json",
success(res){
alert(res.msg);
if(res.code === 0) location.reload();
},
error(){alert(currentLang==='zh'?"编辑保存失败":"Edit save failed")}
})
});
// 修改工单状态
$(document).on("change", ".status-select", function(){
const tr = $(this).closest("tr");
const id = tr.data("id");
const status = $(this).val();
$.ajax({
url: apiOrder + "?action=update_status",
method: "POST",
contentType: "application/json",
data: JSON.stringify({id,status}),
dataType: "json",
success(res){
if(res.code !== 0) alert(res.msg);
else location.reload();
}
})
});
// 管理员分发工单
$(document).on("change", ".assign-user", function(){
const tr = $(this).closest("tr");
const id = tr.data("id");
const assignUid = $(this).val();
$.ajax({
url: apiOrder + "?action=assign_order",
method: "POST",
contentType: "application/json",
data: JSON.stringify({id,assign_uid:assignUid}),
dataType: "json",
success(res){
if(res.code !== 0) alert(res.msg);
else location.reload();
}
})
});
// 顶部时间
function updateTime() {
const now = new Date();
const Y = now.getFullYear();
const M = String(now.getMonth() + 1).padStart(2, '0');
const D = String(now.getDate()).padStart(2, '0');
const h = String(now.getHours()).padStart(2, '0');
const m = String(now.getMinutes()).padStart(2, '0');
const s = String(now.getSeconds()).padStart(2, '0');
$("#updateTime").text(`${Y}-${M}-${D} ${h}:${m}:${s}`);
}
function loadAllData(){
updateTime();
}
$(function() {
loadAllData();
setInterval(updateTime, 1000);
$("#logoutBtn").click(function(){location.href="logout.php";})
});
</script>
</body>
</html>