606 lines
18 KiB
Plaintext
606 lines
18 KiB
Plaintext
<?php
|
||
session_start();
|
||
// 会话超时:30分钟无操作自动登出,和dashboard逻辑统一
|
||
$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";
|
||
$conn = mysqli_connect($dbHost, $dbUser, $dbPwd, $dbName);
|
||
$configSql = "SELECT k,v FROM sys_config";
|
||
$configRes = mysqli_query($conn, $configSql);
|
||
$sysConfig = [];
|
||
while ($row = mysqli_fetch_assoc($configRes)) {
|
||
$sysConfig[$row['k']] = $row['v'];
|
||
}
|
||
mysqli_close($conn);
|
||
|
||
// 读取已有配置默认值
|
||
$pageTitle = $sysConfig['page_title'] ?? "告警监控系统";
|
||
$themeColor = $sysConfig['theme_color'] ?? "#409eff";
|
||
$pageSize = $sysConfig['page_size'] ?? "20";
|
||
$footerText = $sysConfig['footer_text'] ?? "";
|
||
$sidebarLinks = $sysConfig['sidebar_links'] ?? "";
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>系统后台管理 - Advantest 爱德万测试运维告警平台</title>
|
||
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
|
||
<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;
|
||
}
|
||
/* 侧边栏 同dashboard深蓝色侧边 */
|
||
.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;
|
||
}
|
||
/* 顶部导航栏 和dashboard完全一致 */
|
||
.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{
|
||
color:#475569;
|
||
display:flex;
|
||
align-items:center;
|
||
gap: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;
|
||
}
|
||
.btn-danger{
|
||
background:#f56c6c;
|
||
color:#fff;
|
||
}
|
||
.btn-danger:hover{
|
||
background:#e53e3e;
|
||
}
|
||
/* 页面容器 */
|
||
.container{
|
||
padding:36px 40px;
|
||
max-width:100%;
|
||
flex:1;
|
||
}
|
||
.page-title{
|
||
font-size:24px;
|
||
font-weight:700;
|
||
color:#152c5b;
|
||
margin-bottom:26px;
|
||
display:flex;
|
||
align-items:center;
|
||
gap:12px;
|
||
}
|
||
.page-title i{
|
||
color:#2563eb;
|
||
font-size:26px;
|
||
}
|
||
/* Tab切换 */
|
||
.tab-box{
|
||
display:flex;
|
||
border-bottom:1px solid #eef2fb;
|
||
margin-bottom:36px;
|
||
}
|
||
.tab-item{
|
||
padding:14px 26px;
|
||
cursor:pointer;
|
||
font-size:15px;
|
||
color:#64748b;
|
||
border-bottom:3px solid transparent;
|
||
transition:0.2s;
|
||
}
|
||
.tab-item.active{
|
||
color:#2563eb;
|
||
border-bottom:3px solid #2563eb;
|
||
font-weight:600;
|
||
}
|
||
.tab-item:hover:not(.active){
|
||
color:#152c5b;
|
||
}
|
||
/* 统一企业卡片样式,和dashboard base-card完全一致 */
|
||
.card{
|
||
background:#fff;
|
||
border-radius:16px;
|
||
padding:32px;
|
||
margin-bottom:36px;
|
||
box-shadow:0 3px 18px rgba(21,44,91,0.06);
|
||
border:1px solid #eef2fb;
|
||
}
|
||
.card h3{
|
||
display:flex;
|
||
align-items:center;
|
||
gap:10px;
|
||
margin-bottom:26px;
|
||
padding-bottom:16px;
|
||
border-bottom:1px solid #eef2fb;
|
||
font-size:19px;
|
||
font-weight:600;
|
||
color:#152c5b;
|
||
}
|
||
.card h3 i{
|
||
color:#2563eb;
|
||
font-size:20px;
|
||
}
|
||
.form-row{
|
||
margin-bottom:20px;
|
||
display:flex;
|
||
align-items:center;
|
||
gap:12px;
|
||
flex-wrap:wrap;
|
||
}
|
||
.form-row label{
|
||
width:160px;
|
||
font-size:14px;
|
||
color:#475569;
|
||
font-weight:500;
|
||
}
|
||
.form-row input,.form-row textarea{
|
||
padding:10px 14px;
|
||
border:1px solid #dcdfe6;
|
||
border-radius:8px;
|
||
flex:1;
|
||
max-width:480px;
|
||
font-size:14px;
|
||
}
|
||
.form-row textarea{
|
||
min-height:120px;
|
||
resize:vertical;
|
||
}
|
||
.tip-text{
|
||
font-size:13px;
|
||
color:#94a3b8;
|
||
margin-top:-12px;
|
||
margin-bottom:16px;
|
||
padding-left:160px;
|
||
}
|
||
/* 提示消息框 */
|
||
#msg{
|
||
margin:20px 0;
|
||
padding:12px 16px;
|
||
border-radius:8px;
|
||
display:none;
|
||
font-size:14px;
|
||
}
|
||
.success{
|
||
background:#dcfce7;
|
||
color:#16a34a;
|
||
border:1px solid #bbf7d0;
|
||
}
|
||
.error{
|
||
background:#fee2e2;
|
||
color:#dc2626;
|
||
border:1px solid #fecdd3;
|
||
}
|
||
/* JSON返回结果框 */
|
||
#result{
|
||
margin-top:20px;
|
||
padding:20px;
|
||
background:#1e1e1e;
|
||
color:#fff;
|
||
border-radius:12px;
|
||
white-space:pre-wrap;
|
||
min-height:160px;
|
||
font-family:Consolas,monospace;
|
||
font-size:13px;
|
||
}
|
||
.hide{display:none}
|
||
.link-group{
|
||
margin-top:30px;
|
||
padding-top:20px;
|
||
border-top:1px solid #eef2fb;
|
||
display:flex;
|
||
gap:20px;
|
||
}
|
||
.link-group a{
|
||
color:#2563eb;
|
||
text-decoration:none;
|
||
display:flex;
|
||
align-items:center;
|
||
gap:6px;
|
||
}
|
||
.link-group a:hover{
|
||
text-decoration:underline;
|
||
}
|
||
/* 响应式适配 和dashboard统一 */
|
||
@media (max-width:1440px){
|
||
}
|
||
@media (max-width:992px){
|
||
.wrap-main{flex-direction:column;}
|
||
.sidebar{width:100%;height:auto}
|
||
}
|
||
@media (max-width:768px){
|
||
.header{padding:16px 24px;flex-direction:column;gap:16px;align-items:flex-start}
|
||
.header-right{flex-wrap:wrap}
|
||
.container{padding:24px}
|
||
.card{padding:24px}
|
||
.form-row{flex-direction:column;align-items:flex-start}
|
||
.form-row label{width:auto}
|
||
.form-row input,.form-row textarea{width:100%;max-width:100%}
|
||
.tip-text{padding-left:0}
|
||
.tab-item{padding:12px 16px}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap-main">
|
||
<!-- 左侧侧边栏 -->
|
||
<div class="sidebar">
|
||
<div class="sidebar-brand">
|
||
<div class="sidebar-brand-en">Advantest</div>
|
||
<div class="sidebar-brand-cn">运维监控管理后台</div>
|
||
</div>
|
||
<div class="sidebar-menu">
|
||
<div class="menu-title">系统管理</div>
|
||
<div class="menu-item active" data-tab="pwd">
|
||
<i class="fa fa-key"></i>
|
||
<span>修改登录密码</span>
|
||
</div>
|
||
<div class="menu-item" data-tab="theme">
|
||
<i class="fa fa-paint-brush"></i>
|
||
<span>界面外观配置</span>
|
||
</div>
|
||
<div class="menu-item" data-tab="link">
|
||
<i class="fa fa-link"></i>
|
||
<span>侧边栏外链管理</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">系统后台管理面板</div>
|
||
</div>
|
||
</div>
|
||
<div class="header-right">
|
||
<span class="user-info"><i class="fa fa-user-circle"></i>当前用户:<?php echo $userName; ?>(<?php echo $roleText; ?>)</span>
|
||
<button class="btn-base btn-outline" onclick="location.reload()"><i class="fa fa-refresh"></i>刷新配置</button>
|
||
<button class="btn-base btn-primary" onclick="location.href='dashboard.php'"><i class="fa fa-line-chart"></i>告警监控大屏</button>
|
||
<button class="btn-base btn-danger" onclick="location.href='logout.php'"><i class="fa fa-sign-out"></i>退出登录</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="container">
|
||
<div class="page-title"><i class="fa fa-cog"></i>系统全局配置管理</div>
|
||
|
||
<!-- Tab切换 -->
|
||
<div class="tab-box">
|
||
<div class="tab-item active" data-tab="pwd">修改登录密码</div>
|
||
<div class="tab-item" data-tab="theme">界面外观配置</div>
|
||
<div class="tab-item" data-tab="link">侧边栏外链管理</div>
|
||
</div>
|
||
|
||
<!-- 1 修改密码模块 BCrypt兼容 -->
|
||
<div class="card tab-content" id="tab-pwd">
|
||
<h3><i class="fa fa-key"></i>账户密码修改(BCrypt哈希加密,与登录算法统一)</h3>
|
||
<div class="form-row">
|
||
<label>原登录密码:</label>
|
||
<input type="password" id="old_pwd" placeholder="输入当前正在使用的密码">
|
||
</div>
|
||
<div class="tip-text">输入你现在登录的密码用于身份校验</div>
|
||
<div class="form-row">
|
||
<label>新密码:</label>
|
||
<input type="password" id="new_pwd" placeholder="设置全新登录密码">
|
||
</div>
|
||
<div class="form-row">
|
||
<label>确认新密码:</label>
|
||
<input type="password" id="re_pwd" placeholder="再次输入新密码,保持一致">
|
||
</div>
|
||
<div class="form-row">
|
||
<button class="btn-base btn-primary" onclick="updatePwd()"><i class="fa fa-check"></i>提交修改密码</button>
|
||
</div>
|
||
<div id="msg"></div>
|
||
<div id="result"></div>
|
||
</div>
|
||
|
||
<!-- 2 界面外观配置(保存后dashboard实时生效) -->
|
||
<div class="card tab-content hide" id="tab-theme">
|
||
<h3><i class="fa fa-paint-brush"></i>监控大屏界面外观全局配置</h3>
|
||
<div class="form-row">
|
||
<label>页面标题:</label>
|
||
<input id="page_title" value="<?php echo htmlspecialchars($pageTitle); ?>" placeholder="告警监控系统">
|
||
</div>
|
||
<div class="form-row">
|
||
<label>主题主色值:</label>
|
||
<input id="theme_color" value="<?php echo htmlspecialchars($themeColor); ?>" placeholder="#409eff">
|
||
</div>
|
||
<div class="form-row">
|
||
<label>表格每页展示条数:</label>
|
||
<input id="page_size" value="<?php echo htmlspecialchars($pageSize); ?>" placeholder="20">
|
||
</div>
|
||
<div class="form-row">
|
||
<label>页面底部自定义文案:</label>
|
||
<textarea id="footer_text"><?php echo htmlspecialchars($footerText); ?></textarea>
|
||
</div>
|
||
<div class="form-row">
|
||
<button class="btn-base btn-success" onclick="saveTheme()"><i class="fa fa-save"></i>保存外观配置</button>
|
||
</div>
|
||
<div class="tip-text">保存后刷新告警监控大屏dashboard.php即可生效</div>
|
||
<div id="msg"></div>
|
||
<div id="result"></div>
|
||
</div>
|
||
|
||
<!-- 3 侧边栏外链管理(保存后dashboard侧边同步更新) -->
|
||
<div class="card tab-content hide" id="tab-link">
|
||
<h3><i class="fa fa-link"></i>监控大屏侧边导航外链配置</h3>
|
||
<div class="form-row">
|
||
<label>外链列表(格式:名称|地址,一行一条):</label>
|
||
<textarea id="sidebar_links"><?php echo htmlspecialchars($sidebarLinks); ?></textarea>
|
||
</div>
|
||
<div class="tip-text">示例:Prometheus|http://10.150.117.190:9090<br>保存后刷新dashboard侧边栏立即加载</div>
|
||
<div class="form-row">
|
||
<button class="btn-base btn-success" onclick="saveLink()"><i class="fa fa-save"></i>保存侧边外链配置</button>
|
||
</div>
|
||
<div id="msg"></div>
|
||
<div id="result"></div>
|
||
</div>
|
||
|
||
<!-- 底部跳转链接 -->
|
||
<div class="link-group">
|
||
<a href="./api/dev_panel.php" target="_blank"><i class="fa fa-code"></i>进入开发者调试面板(API可视化调用)</a>
|
||
<a href="dashboard.php"><i class="fa fa-line-chart"></i>返回告警监控总览大屏</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 相对路径接口,适配站点部署
|
||
const api = "./api/index.php";
|
||
const msgBox = document.getElementById("msg");
|
||
const resultBox = document.getElementById("result");
|
||
|
||
// Tab切换逻辑
|
||
document.querySelectorAll(".tab-item").forEach(item=>{
|
||
item.onclick = ()=>{
|
||
document.querySelectorAll(".tab-item").forEach(t=>t.classList.remove("active"));
|
||
item.classList.add("active");
|
||
const tabId = item.dataset.tab;
|
||
document.querySelectorAll(".tab-content").forEach(c=>c.classList.add("hide"));
|
||
document.getElementById("tab-"+tabId).classList.remove("hide");
|
||
msgBox.style.display = "none";
|
||
resultBox.innerText = "";
|
||
}
|
||
})
|
||
// 侧边菜单同步Tab切换
|
||
$(".menu-item").click(function(){
|
||
const tabId = $(this).data("tab");
|
||
$(".tab-item").removeClass("active");
|
||
$(`.tab-item[data-tab="${tabId}"]`).addClass("active");
|
||
$(".tab-content").addClass("hide");
|
||
$("#tab-"+tabId).removeClass("hide");
|
||
msgBox.style.display = "none";
|
||
resultBox.innerText = "";
|
||
})
|
||
|
||
// 通用提示弹窗
|
||
function showMsg(text, type="success"){
|
||
msgBox.className = type;
|
||
msgBox.innerText = text;
|
||
msgBox.style.display = "block";
|
||
}
|
||
|
||
// 1 修改密码接口请求
|
||
function updatePwd(){
|
||
const old = document.getElementById("old_pwd").value.trim();
|
||
const new1 = document.getElementById("new_pwd").value.trim();
|
||
const new2 = document.getElementById("re_pwd").value.trim();
|
||
if(!old || !new1 || !new2) return showMsg("所有密码输入项不能为空","error");
|
||
if(new1 !== new2) return showMsg("两次输入的新密码不一致,请核对","error");
|
||
const params = new URLSearchParams();
|
||
params.append("act","change_pwd");
|
||
params.append("old_pwd",old);
|
||
params.append("new_pwd",new1);
|
||
fetch(`${api}?${params.toString()}`)
|
||
.then(r=>r.json())
|
||
.then(json=>{
|
||
resultBox.innerText = JSON.stringify(json,null,2);
|
||
if(json.code===0){
|
||
showMsg("密码修改成功,即将跳转登录页重新验证");
|
||
setTimeout(()=>location.href="login.php",1800);
|
||
}else{
|
||
showMsg(json.msg,"error");
|
||
}
|
||
})
|
||
.catch(e=>{
|
||
showMsg("接口请求失败:"+e,"error");
|
||
})
|
||
}
|
||
|
||
// 2 保存外观配置(存入sys_config,dashboard读取渲染)
|
||
function saveTheme(){
|
||
const params = new URLSearchParams();
|
||
params.append("act","save_theme");
|
||
params.append("title",document.getElementById("page_title").value);
|
||
params.append("color",document.getElementById("theme_color").value);
|
||
params.append("pagesize",document.getElementById("page_size").value);
|
||
params.append("footer",document.getElementById("footer_text").value);
|
||
fetch(`${api}?${params.toString()}`)
|
||
.then(r=>r.json())
|
||
.then(json=>{
|
||
resultBox.innerText = JSON.stringify(json,null,2);
|
||
if(json.code===0){
|
||
showMsg("外观配置保存成功,刷新监控大屏即可生效");
|
||
}else{
|
||
showMsg(json.msg,"error");
|
||
}
|
||
})
|
||
.catch(e=>{
|
||
showMsg("接口请求失败:"+e,"error");
|
||
})
|
||
}
|
||
|
||
// 3 保存侧边外链(存入sys_config,dashboard侧边读取渲染)
|
||
function saveLink(){
|
||
const params = new URLSearchParams();
|
||
params.append("act","save_sidebar_link");
|
||
params.append("link_text",document.getElementById("sidebar_links").value);
|
||
fetch(`${api}?${params.toString()}`)
|
||
.then(r=>r.json())
|
||
.then(json=>{
|
||
resultBox.innerText = JSON.stringify(json,null,2);
|
||
if(json.code===0){
|
||
showMsg("侧边外链保存成功,刷新监控大屏侧边栏立即更新");
|
||
}else{
|
||
showMsg(json.msg,"error");
|
||
}
|
||
})
|
||
.catch(e=>{
|
||
showMsg("接口请求失败:"+e,"error");
|
||
})
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|