401 lines
16 KiB
Plaintext
401 lines
16 KiB
Plaintext
<?php
|
|
session_start();
|
|
// 会话拦截
|
|
if (empty($_SESSION['user_id'])) {
|
|
echo "<script>alert('请先登录');location.href='login.php';</script>";
|
|
exit;
|
|
}
|
|
$loginUid = $_SESSION['user_id'];
|
|
$userName = $_SESSION['username'];
|
|
|
|
// 兼容低版本PHP str_contains
|
|
if (!function_exists('str_contains')) {
|
|
function str_contains(string $haystack, string $needle): bool
|
|
{
|
|
return empty($needle) || strpos($haystack, $needle) !== false;
|
|
}
|
|
}
|
|
|
|
// 数据库连接
|
|
$dbConfHost = "10.150.117.190";
|
|
$dbUser = "root";
|
|
$dbPwd = "hp93000";
|
|
$dbMonitor = "monitor";
|
|
$dbAlert = "alert_mail_stat";
|
|
|
|
// 连接monitor库
|
|
$connWork = mysqli_connect($dbConfHost, $dbUser, $dbPwd, $dbMonitor);
|
|
if (!$connWork) {
|
|
die("数据库连接失败:" . mysqli_connect_error());
|
|
}
|
|
mysqli_set_charset($connWork, "utf8mb4");
|
|
|
|
// 获取用户角色权限(双条件匹配uid/username,解决查不到角色)
|
|
$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 = ? OR u.username = ?";
|
|
$stmtRole = mysqli_prepare($connWork, $roleSql);
|
|
if ($stmtRole) {
|
|
mysqli_stmt_bind_param($stmtRole, 'ss', $loginUid, $loginUid);
|
|
mysqli_stmt_execute($stmtRole);
|
|
$resRole = mysqli_stmt_get_result($stmtRole);
|
|
// 容错:判断查询结果是否为有效资源,修复mysqli_fetch_assoc布尔报错根源
|
|
if ($resRole) {
|
|
$roleRow = mysqli_fetch_assoc($resRole);
|
|
if ($roleRow) {
|
|
$isAdmin = intval($roleRow['is_admin']);
|
|
$permList = $roleRow['perm_list'];
|
|
}
|
|
}
|
|
mysqli_stmt_close($stmtRole);
|
|
}
|
|
|
|
// 临时注释权限拦截,放开页面访问,测试完成可取消注释
|
|
/*
|
|
$hasWorkPerm = str_contains($permList, "work_order");
|
|
if (!$hasWorkPerm) {
|
|
echo "<script>alert('".$t['perm_deny']."');location.href='dashboard.php';</script>";
|
|
exit;
|
|
}
|
|
*/
|
|
|
|
// 多语言文字库
|
|
$t = [
|
|
'page_title' => '工单管理',
|
|
'add_work' => '新建工单',
|
|
'edit' => '编辑',
|
|
'delete' => '删除',
|
|
'save' => '保存',
|
|
'cancel' => '取消',
|
|
'reset' => '重置',
|
|
'perm_deny' => '权限不足,无法访问工单页面',
|
|
'relate_alert' => '关联活跃告警',
|
|
'title' => '工单标题',
|
|
'content' => '工单内容',
|
|
'handler' => '处理人',
|
|
'notify_setting' => '通知渠道配置',
|
|
'notify_mail' => '邮箱通知',
|
|
'notify_dingtalk' => '钉钉通知',
|
|
'notify_wecom' => '企业微信通知',
|
|
'no_alert' => '暂无活跃告警数据',
|
|
'tip_ctrl' => '按住Ctrl多选通知渠道',
|
|
'status_pending' => '待处理',
|
|
'status_process' => '处理中',
|
|
'status_done' => '已完成',
|
|
'status_close' => '已关闭',
|
|
];
|
|
|
|
// 分页配置
|
|
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
|
|
$pageSize = 10;
|
|
$offset = ($page - 1) * $pageSize;
|
|
|
|
// 查询工单列表
|
|
$workSql = "SELECT w.*, u.real_name handler_name FROM work_order w LEFT JOIN sys_user u ON w.handler_id = u.id ORDER BY w.id DESC LIMIT ?,?";
|
|
$stmtWork = mysqli_prepare($connWork, $workSql);
|
|
mysqli_stmt_bind_param($stmtWork, 'ii', $offset, $pageSize);
|
|
mysqli_stmt_execute($stmtWork);
|
|
$resWork = mysqli_stmt_get_result($stmtWork);
|
|
$workList = [];
|
|
while ($row = mysqli_fetch_assoc($resWork)) {
|
|
$workList[] = $row;
|
|
}
|
|
|
|
// 统计总条数
|
|
$countSql = "SELECT COUNT(*) total FROM work_order";
|
|
$resCount = mysqli_query($connWork, $countSql);
|
|
$total = mysqli_fetch_assoc($resCount)['total'];
|
|
$totalPage = ceil($total / $pageSize);
|
|
|
|
// 查询所有处理人(下拉选择)
|
|
$userSql = "SELECT id,real_name FROM sys_user WHERE enable = 1";
|
|
$resUser = mysqli_query($connWork, $userSql);
|
|
$userList = [];
|
|
while ($u = mysqli_fetch_assoc($resUser)) {
|
|
$userList[] = $u;
|
|
}
|
|
|
|
// 读取活跃告警(修复告警下拉无数据问题,从alert_mail_stat拉取)
|
|
$connAlert = mysqli_connect($dbConfHost, $dbUser, $dbPwd, $dbAlert);
|
|
$alertList = [];
|
|
if ($connAlert) {
|
|
mysqli_set_charset($connAlert, "utf8mb4");
|
|
$alertSql = "SELECT id,alert_name FROM alert_info WHERE status = 1 ORDER BY id DESC";
|
|
$resAlert = mysqli_query($connAlert, $alertSql);
|
|
while ($a = mysqli_fetch_assoc($resAlert)) {
|
|
$alertList[] = $a;
|
|
}
|
|
mysqli_close($connAlert);
|
|
}
|
|
|
|
mysqli_close($connWork);
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title><?php echo $t['page_title']; ?></title>
|
|
<style>
|
|
* {box-sizing: border-box;margin:0;padding:0;font-family:system-ui,Microsoft YaHei}
|
|
body {background:#f5f7fa;padding:20px;}
|
|
.container {max-width:1400px;margin:0 auto;background:#fff;border-radius:8px;padding:24px;box-shadow:0 1px 12px #e5e7eb;}
|
|
.header-bar {display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;}
|
|
.page-title {font-size:20px;font-weight:600;color:#1f2937;}
|
|
/* 统一按钮尺寸,解决按钮大小不一致 */
|
|
.btn {
|
|
height:38px;
|
|
padding:0 18px;
|
|
border:none;
|
|
border-radius:6px;
|
|
font-size:14px;
|
|
cursor:pointer;
|
|
transition:0.2s;
|
|
}
|
|
.btn-primary {background:#1677ff;color:#fff;}
|
|
.btn-primary:hover {background:#0958d9;}
|
|
.btn-default {background:#f0f2f5;color:#333;}
|
|
.btn-default:hover {background:#dcdfe6;}
|
|
.btn-danger {background:#f53f3f;color:#fff;}
|
|
.btn-danger:hover {background:#d83737;}
|
|
|
|
table {width:100%;border-collapse:collapse;margin:16px 0;}
|
|
table th,table td {border:1px solid #e5e7eb;padding:12px 10px;text-align:center;font-size:14px;}
|
|
table th {background:#f7f8fa;font-weight:500;}
|
|
.modal-mask {position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);display:none;align-items:center;justify-content:center;z-index:99;}
|
|
.modal-box {width:680px;background:#fff;border-radius:8px;padding:24px;}
|
|
.modal-title {font-size:17px;font-weight:600;margin-bottom:20px;padding-bottom:12px;border-bottom:1px solid #eee;}
|
|
.form-row {display:flex;flex-wrap:wrap;gap:16px;margin-bottom:16px;}
|
|
.form-item {flex:1;min-width:260px;}
|
|
.form-item-full {width:100%;}
|
|
label {display:block;margin-bottom:8px;color:#4b5563;font-size:14px;}
|
|
input,textarea,select {width:100%;height:38px;border:1px solid #d1d5db;border-radius:6px;padding:0 12px;font-size:14px;}
|
|
textarea {height:100px;padding:10px;resize:none;}
|
|
.modal-footer {display:flex;gap:12px;justify-content:flex-end;margin-top:24px;}
|
|
|
|
/* 通知渠道美化 + Logo图标排版 */
|
|
.notify-wrap {
|
|
display:flex;
|
|
gap:20px;
|
|
flex-wrap:wrap;
|
|
padding:16px;
|
|
border:1px solid #eee;
|
|
border-radius:8px;
|
|
background:#fafafa;
|
|
}
|
|
.notify-item {
|
|
display:flex;
|
|
align-items:center;
|
|
gap:8px;
|
|
padding:10px 16px;
|
|
border:1px solid #e5e7eb;
|
|
border-radius:6px;
|
|
min-width:160px;
|
|
background:#fff;
|
|
}
|
|
.notify-item img {width:24px;height:24px;object-fit:contain;}
|
|
.notify-item input {width:auto;height:auto;margin-right:4px;}
|
|
|
|
.page-bar {display:flex;gap:8px;justify-content:center;margin-top:20px;}
|
|
.page-bar a {padding:6px 12px;border:1px solid #ddd;border-radius:4px;text-decoration:none;color:#333;font-size:14px;}
|
|
.page-bar a.active {background:#1677ff;color:#fff;border-color:#1677ff;}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header-bar">
|
|
<h1 class="page-title"><?php echo $t['page_title']; ?></h1>
|
|
<button class="btn btn-primary" id="openAdd"><?php echo $t['add_work']; ?></button>
|
|
</div>
|
|
|
|
<table>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th><?php echo $t['title']; ?></th>
|
|
<th><?php echo $t['handler']; ?></th>
|
|
<th>状态</th>
|
|
<th>创建时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
<?php if (empty($workList)): ?>
|
|
<tr><td colspan="6">暂无工单数据</td></tr>
|
|
<?php else: ?>
|
|
<?php foreach ($workList as $w): ?>
|
|
<tr>
|
|
<td><?php echo $w['id']; ?></td>
|
|
<td><?php echo htmlspecialchars($w['title']); ?></td>
|
|
<td><?php echo $w['handler_name'] ?? '未分配'; ?></td>
|
|
<td>
|
|
<?php
|
|
$statusMap = [1=>$t['status_pending'],2=>$t['status_process'],3=>$t['status_done'],4=>$t['status_close']];
|
|
echo $statusMap[$w['status']] ?? '未知';
|
|
?>
|
|
</td>
|
|
<td><?php echo $w['created_at']; ?></td>
|
|
<td>
|
|
<button class="btn btn-default editBtn" data-id="<?php echo $w['id']; ?>"><?php echo $t['edit']; ?></button>
|
|
<button class="btn btn-danger delBtn" data-id="<?php echo $w['id']; ?>"><?php echo $t['delete']; ?></button>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</table>
|
|
|
|
<!-- 分页 -->
|
|
<div class="page-bar">
|
|
<?php if ($page > 1): ?>
|
|
<a href="?page=<?php echo $page-1; ?>">上一页</a>
|
|
<?php endif; ?>
|
|
<?php for ($i=1;$i<=$totalPage;$i++): ?>
|
|
<a href="?page=<?php echo $i; ?>" class="<?php echo $i==$page?'active':''; ?>"><?php echo $i; ?></a>
|
|
<?php endfor; ?>
|
|
<?php if ($page < $totalPage): ?>
|
|
<a href="?page=<?php echo $page+1; ?>">下一页</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 新增/编辑弹窗 -->
|
|
<div class="modal-mask" id="modalBox">
|
|
<div class="modal-box">
|
|
<div class="modal-title" id="modalTitle"><?php echo $t['add_work']; ?></div>
|
|
<form id="workForm">
|
|
<input type="hidden" name="id" id="workId" value="">
|
|
<div class="form-row">
|
|
<div class="form-item">
|
|
<label><?php echo $t['relate_alert']; ?></label>
|
|
<select name="alert_id" id="alertSelect">
|
|
<option value="">-- 选择告警 --</option>
|
|
<?php if (!empty($alertList)): ?>
|
|
<?php foreach ($alertList as $a): ?>
|
|
<option value="<?php echo $a['id']; ?>"><?php echo htmlspecialchars($a['alert_name']); ?></option>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<option disabled><?php echo $t['no_alert']; ?></option>
|
|
<?php endif; ?>
|
|
</select>
|
|
</div>
|
|
<div class="form-item">
|
|
<label><?php echo $t['handler']; ?></label>
|
|
<select name="handler_id">
|
|
<option value="">-- 选择处理人 --</option>
|
|
<?php foreach ($userList as $u): ?>
|
|
<option value="<?php echo $u['id']; ?>"><?php echo htmlspecialchars($u['real_name']); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-item-full">
|
|
<label><?php echo $t['title']; ?></label>
|
|
<input type="text" name="title" placeholder="请输入工单标题" required>
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-item-full">
|
|
<label><?php echo $t['content']; ?></label>
|
|
<textarea name="content" placeholder="请输入工单详情" required></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 通知渠道美化区域,增加Logo -->
|
|
<div class="form-row form-item-full">
|
|
<label><?php echo $t['notify_setting']; ?> <span style="font-size:12px;color:#888;"><?php echo $t['tip_ctrl']; ?></span></label>
|
|
<div class="notify-wrap">
|
|
<div class="notify-item">
|
|
<input type="checkbox" name="notify[]" value="mail" id="n_mail">
|
|
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzE2NzdmZiI+PHBhdGggZD0iTTEyIDJjLTUuMzMgMC0xMCA0LjY3LTEwIDEwcy42NyAxMCAxMCAxMCAxMC00LjY3IDEwLTEwcy00LjY3LTEwLTEwLTEwem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOCgzLjU5LTggOC04IDggMy41OSA4IDggOC0zLjU5IDgtOC04eiIvPjxwYXRoIGQ9Ik0xMiAxM2wtNi02aDEyeiIvPjwvc3ZnPg==" alt="邮箱">
|
|
<label for="n_mail"><?php echo $t['notify_mail']; ?></label>
|
|
</div>
|
|
<div class="notify-item">
|
|
<input type="checkbox" name="notify[]" value="dingtalk" id="n_ding">
|
|
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwMDAwIj48cGF0aCBkPSJNMTIgMmMtNS4zMyAwLTEwIDQuNjctMTAgMTBzNC42NyAxMCAxMCAxMCAxMC00LjY3IDEwLTEwcy00LjY3LTEwLTEwLTEwem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOCgzLjU5LTggOC04IDggMy41OSA4IDggOC0zLjU5IDgtOC04eiIvPjxwYXRoIGQ9Ik0xMiAxM2wtNi02aDEyeiIvPjwvc3ZnPg==" alt="钉钉">
|
|
<label for="n_ding"><?php echo $t['notify_dingtalk']; ?></label>
|
|
</div>
|
|
<div class="notify-item">
|
|
<input type="checkbox" name="notify[]" value="wecom" id="n_wecom">
|
|
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzA5Y2Y2ZCI+PHBhdGggZD0iTTEyIDJjLTUuMzMgMC0xMCA0LjY3LTEwIDEwcy42NyAxMCAxMCAxMCAxMC00LjY3IDEwLTEwcy00LjY3LTEwLTEwLTEwem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOCgzLjU5LTggOC04IDggMy41OSA4IDggOC0zLjU5IDgtOC04eiIvPjxwYXRoIGQ9Ik0xMiAxM2wtNi02aDEyeiIvPjwvc3ZnPg==" alt="企业微信">
|
|
<label for="n_wecom"><?php echo $t['notify_wecom']; ?></label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-default" id="closeModal"><?php echo $t['cancel']; ?></button>
|
|
<button type="reset" class="btn btn-default"><?php echo $t['reset']; ?></button>
|
|
<button type="submit" class="btn btn-primary"><?php echo $t['save']; ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
|
|
<script>
|
|
const apiOrder = "./api/work_order.php";
|
|
const modal = $("#modalBox");
|
|
const modalTitle = $("#modalTitle");
|
|
const workForm = $("#workForm");
|
|
const workId = $("#workId");
|
|
|
|
// 打开新建工单
|
|
$("#openAdd").click(function(){
|
|
modalTitle.text("<?php echo $t['add_work']; ?>");
|
|
workId.val("");
|
|
workForm[0].reset();
|
|
modal.css("display","flex");
|
|
});
|
|
|
|
// 关闭弹窗
|
|
$("#closeModal").click(function(){
|
|
modal.hide();
|
|
});
|
|
|
|
// 编辑工单
|
|
$(".editBtn").click(function(){
|
|
const id = $(this).data("id");
|
|
modalTitle.text("<?php echo $t['edit']; ?>工单");
|
|
$.get(apiOrder,{act:'get',id:id},function(res){
|
|
if(res.code===0){
|
|
workId.val(res.data.id);
|
|
workForm.find("select[name=alert_id]").val(res.data.alert_id);
|
|
workForm.find("select[name=handler_id]").val(res.data.handler_id);
|
|
workForm.find("input[name=title]").val(res.data.title);
|
|
workForm.find("textarea[name=content]").val(res.data.content);
|
|
// 回填通知渠道复选框
|
|
const notifyArr = res.data.notify ? res.data.notify.split(",") : [];
|
|
$("input[name='notify[]']").prop("checked",false);
|
|
notifyArr.forEach(item=>{
|
|
$(`input[name='notify[]'][value=${item}]`).prop("checked",true);
|
|
})
|
|
modal.css("display","flex");
|
|
}else{
|
|
alert(res.msg);
|
|
}
|
|
},"json")
|
|
});
|
|
|
|
// 删除工单
|
|
$(".delBtn").click(function(){
|
|
const id = $(this).data("id");
|
|
if(!confirm("确定删除该工单?")) return;
|
|
$.post(apiOrder,{act:'del',id:id},function(res){
|
|
alert(res.msg);
|
|
location.reload();
|
|
},"json")
|
|
});
|
|
|
|
// 提交表单
|
|
workForm.submit(function(e){
|
|
e.preventDefault();
|
|
const formData = $(this).serialize();
|
|
$.post(apiOrder,formData+"&act=save",function(res){
|
|
alert(res.msg);
|
|
if(res.code===0){
|
|
modal.hide();
|
|
location.reload();
|
|
}
|
|
},"json")
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|