2065 lines
82 KiB
HTML
2065 lines
82 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>网易大神审核数据监控看板</title>
|
||
<link rel="icon" href="/static/ds-favicon.ico" type="image/x-icon">
|
||
<script src="https://cdn.bootcdn.net/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>
|
||
<style>
|
||
body {
|
||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||
background-color: #f5f5f5;
|
||
margin: 0;
|
||
padding: 0;
|
||
color: #333;
|
||
}
|
||
|
||
.header {
|
||
background-color: #1890ff;
|
||
color: white;
|
||
padding: 1rem;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.header-title {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.header h1 {
|
||
margin: 0;
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.version-display {
|
||
font-size: 0.8rem;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
font-weight: normal;
|
||
}
|
||
|
||
.header-buttons {
|
||
display: flex;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.header-buttons button {
|
||
background-color: #2196F3;
|
||
border: none;
|
||
color: white;
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
transition: background-color 0.3s;
|
||
font-weight: bold;
|
||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.header-buttons button:hover {
|
||
background-color: #0d8bf2;
|
||
}
|
||
|
||
.container {
|
||
display: flex;
|
||
padding: 1rem;
|
||
flex-wrap: wrap;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.panel {
|
||
flex: 1;
|
||
min-width: 500px;
|
||
background-color: white;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.panel-header {
|
||
background-color: #fafafa;
|
||
padding: 1rem;
|
||
border-bottom: 1px solid #eee;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.panel-header h2 {
|
||
margin: 0;
|
||
font-size: 1.2rem;
|
||
color: #333;
|
||
}
|
||
|
||
.panel-header .last-update {
|
||
font-size: 0.8rem;
|
||
color: #999;
|
||
}
|
||
|
||
.panel-body {
|
||
padding: 1rem;
|
||
}
|
||
|
||
.data-section {
|
||
margin-bottom: 1.5rem;
|
||
padding-bottom: 1.5rem;
|
||
border-bottom: 1px solid #eee;
|
||
}
|
||
|
||
.data-section:last-child {
|
||
border-bottom: none;
|
||
margin-bottom: 0;
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
.data-section h3 {
|
||
margin-top: 0;
|
||
margin-bottom: 1rem;
|
||
color: #666;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.data-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 1rem;
|
||
}
|
||
|
||
.data-card {
|
||
background-color: #f9f9f9;
|
||
border-radius: 4px;
|
||
padding: 1rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.data-card .value {
|
||
font-size: 1.8rem;
|
||
font-weight: bold;
|
||
color: #1890ff;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.data-card .label {
|
||
font-size: 0.9rem;
|
||
color: #666;
|
||
text-align: center;
|
||
}
|
||
|
||
.data-total {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
background-color: #f0f8ff;
|
||
border: 1px solid #d6e9ff;
|
||
border-radius: 4px;
|
||
padding: 1rem;
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.data-total .label {
|
||
font-weight: bold;
|
||
color: #0d6efd;
|
||
}
|
||
|
||
.data-total .value {
|
||
font-size: 1.5rem;
|
||
font-weight: bold;
|
||
color: #0d6efd;
|
||
}
|
||
|
||
.data-coefficient {
|
||
font-size: 0.8rem;
|
||
color: #999;
|
||
margin-top: 0.25rem;
|
||
}
|
||
|
||
.categories {
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.category-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
padding: 0.5rem 0;
|
||
border-bottom: 2px solid #ddd;
|
||
font-weight: bold;
|
||
color: #666;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.category-header .name {
|
||
flex: 2;
|
||
}
|
||
|
||
.category-header .count,
|
||
.category-header .weighted {
|
||
flex: 1;
|
||
text-align: right;
|
||
}
|
||
|
||
.category-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
padding: 0.5rem 0;
|
||
border-bottom: 1px dashed #eee;
|
||
}
|
||
|
||
.category-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.category-item .name {
|
||
flex: 2;
|
||
}
|
||
|
||
.category-item .count,
|
||
.category-item .weighted,
|
||
.category-item .coefficient {
|
||
flex: 1;
|
||
text-align: right;
|
||
}
|
||
|
||
.total-stats {
|
||
background-color: #fff7e6;
|
||
border: 1px solid #ffe7ba;
|
||
border-radius: 8px;
|
||
padding: 1rem;
|
||
margin: 1rem;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.total-stats h2 {
|
||
margin: 0;
|
||
color: #d46b08;
|
||
}
|
||
|
||
.total-stats .total-value {
|
||
font-size: 2rem;
|
||
font-weight: bold;
|
||
color: #d46b08;
|
||
}
|
||
|
||
.alarm-banner {
|
||
background-color: #fff2f0;
|
||
border: 1px solid #ffccc7;
|
||
color: #cf1322;
|
||
padding: 1rem;
|
||
margin: 1rem;
|
||
border-radius: 8px;
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.alarm-banner.active {
|
||
display: flex;
|
||
animation: pulse 2s infinite;
|
||
}
|
||
|
||
.alarm-message {
|
||
font-weight: bold;
|
||
}
|
||
|
||
.alarm-button {
|
||
background-color: #ff4d4f;
|
||
color: white;
|
||
border: none;
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-weight: bold;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0% {
|
||
opacity: 1;
|
||
}
|
||
|
||
50% {
|
||
opacity: 0.8;
|
||
}
|
||
|
||
100% {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.loading {
|
||
text-align: center;
|
||
padding: 2rem;
|
||
color: #999;
|
||
}
|
||
|
||
@media (max-width: 1100px) {
|
||
.panel {
|
||
min-width: 100%;
|
||
}
|
||
}
|
||
|
||
.breeze-settings-button {
|
||
background-color: #4a6da7;
|
||
}
|
||
|
||
.form-content {
|
||
max-height: 400px;
|
||
overflow-y: auto;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.search-group {
|
||
position: sticky;
|
||
top: 0;
|
||
background-color: #fff;
|
||
padding: 5px 0;
|
||
z-index: 10;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
#breeze-search {
|
||
width: 100%;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
/* 对话框样式 */
|
||
.dialog {
|
||
display: none;
|
||
position: fixed;
|
||
z-index: 1000;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
}
|
||
|
||
/* 版本检测对话框样式 */
|
||
.update-available {
|
||
color: #cf1322;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.check-time {
|
||
font-size: 0.8rem;
|
||
color: #999;
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.version-info {
|
||
margin: 1rem 0;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.dialog-button {
|
||
padding: 8px 16px;
|
||
background-color: #2196F3;
|
||
border: none;
|
||
color: white;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-weight: bold;
|
||
margin-top: 1rem;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.dialog-button.update {
|
||
background-color: #52c41a;
|
||
}
|
||
|
||
.dialog-button:hover {
|
||
background-color: #0d8bf2;
|
||
}
|
||
|
||
.dialog-button.update:hover {
|
||
background-color: #3daa08;
|
||
}
|
||
|
||
/* 对话框内容样式 */
|
||
.dialog-content {
|
||
width: 500px;
|
||
background-color: white;
|
||
margin: 100px auto;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.dialog h2 {
|
||
margin-top: 0;
|
||
color: #1890ff;
|
||
}
|
||
|
||
.close {
|
||
color: #aaa;
|
||
float: right;
|
||
font-size: 28px;
|
||
font-weight: bold;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.close:hover {
|
||
color: black;
|
||
}
|
||
|
||
.settings-form {
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.form-group label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.form-group input {
|
||
width: 100%;
|
||
padding: 8px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.settings-form button {
|
||
padding: 8px 16px;
|
||
background-color: #1890ff;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
/* 工具按钮样式 */
|
||
.action-buttons {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 20px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
/* 移除这个通用样式 */
|
||
/*.action-button {
|
||
padding: 8px 16px;
|
||
background-color: #f0f0f0;
|
||
border: 1px solid #ddd;
|
||
color: #333;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
}*/
|
||
|
||
/* 所有按钮使用统一的蓝色背景 */
|
||
.refresh-button,
|
||
.check-now-button,
|
||
.restart-button,
|
||
.test-alarm-button,
|
||
.cms-settings-button,
|
||
.breeze-settings-button,
|
||
#logout-button {
|
||
padding: 8px 16px;
|
||
background-color: #2196F3;
|
||
border: none;
|
||
color: white;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-weight: bold;
|
||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
/* 悬停效果 */
|
||
.refresh-button:hover,
|
||
.check-now-button:hover,
|
||
.restart-button:hover,
|
||
.test-alarm-button:hover,
|
||
.cms-settings-button:hover,
|
||
.breeze-settings-button:hover,
|
||
#logout-button:hover {
|
||
background-color: #0d8bf2;
|
||
}
|
||
|
||
.welcome-message {
|
||
display: none;
|
||
}
|
||
|
||
.welcome-text {
|
||
display: none;
|
||
}
|
||
|
||
/* 添加消息提示样式 */
|
||
.message-container {
|
||
position: fixed;
|
||
top: 16px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 1010;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.message {
|
||
padding: 8px 16px;
|
||
margin-bottom: 8px;
|
||
border-radius: 4px;
|
||
box-shadow: 0 3px 6px -4px rgba(0,0,0,.12), 0 6px 16px 0 rgba(0,0,0,.08);
|
||
background: #fff;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
pointer-events: all;
|
||
font-size: 14px;
|
||
animation: messageSlideDown 0.3s ease-out, messageFadeOut 0.2s ease-out 2.8s forwards;
|
||
}
|
||
|
||
.message.success {
|
||
background: #f6ffed;
|
||
border: 1px solid #b7eb8f;
|
||
color: #52c41a;
|
||
}
|
||
|
||
.message.error {
|
||
background: #fff2f0;
|
||
border: 1px solid #ffccc7;
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
.message.info {
|
||
background: #e6f7ff;
|
||
border: 1px solid #91d5ff;
|
||
color: #1890ff;
|
||
}
|
||
|
||
@keyframes messageSlideDown {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateY(-100%);
|
||
}
|
||
100% {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
@keyframes messageFadeOut {
|
||
0% {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
max-height: 150px;
|
||
}
|
||
100% {
|
||
opacity: 0;
|
||
transform: translateY(-100%);
|
||
max-height: 0;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
}
|
||
|
||
/* 当前用户样式 */
|
||
.current-user {
|
||
padding: 8px 16px;
|
||
background-color: #2196F3;
|
||
border: none;
|
||
color: white;
|
||
border-radius: 4px;
|
||
font-weight: bold;
|
||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||
margin-right: 15px;
|
||
cursor: default; /* 不显示手型光标 */
|
||
}
|
||
|
||
.current-user:hover {
|
||
background-color: #2196F3; /* 保持原色,不改变 */
|
||
}
|
||
|
||
.categories-container {
|
||
margin-top: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.category-item {
|
||
padding: 10px;
|
||
border-bottom: 1px solid #eee;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.category-name {
|
||
font-weight: 500;
|
||
color: #333;
|
||
}
|
||
|
||
.category-stats {
|
||
display: flex;
|
||
gap: 20px;
|
||
}
|
||
|
||
.category-stats span {
|
||
color: #666;
|
||
}
|
||
|
||
.category-stats .count {
|
||
color: #1890ff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.category-stats .weighted {
|
||
color: #52c41a;
|
||
}
|
||
|
||
.weighted-total {
|
||
margin-top: 20px;
|
||
text-align: right;
|
||
}
|
||
|
||
.weighted-total h3 {
|
||
color: #52c41a;
|
||
margin: 0;
|
||
}
|
||
|
||
.user-info {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.user-name {
|
||
font-size: 1rem;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.logout-btn {
|
||
background-color: #ff4d4f;
|
||
border: none;
|
||
color: white;
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.stats-container {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 1rem;
|
||
padding: 1rem;
|
||
background: white;
|
||
}
|
||
|
||
.stats-card {
|
||
flex: 1;
|
||
min-width: 250px;
|
||
background: white;
|
||
border: 1px solid #eee;
|
||
border-radius: 8px;
|
||
padding: 1rem;
|
||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.stats-card h3 {
|
||
margin: 0 0 1rem 0;
|
||
color: #333;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.stats-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.stats-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.stats-label {
|
||
font-size: 0.9rem;
|
||
color: #666;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.stats-value {
|
||
font-size: 1.8rem;
|
||
font-weight: bold;
|
||
color: #1890ff;
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 8px;
|
||
}
|
||
|
||
.weighted-number {
|
||
font-size: 1.2rem;
|
||
color: #999;
|
||
font-weight: normal;
|
||
}
|
||
|
||
.stats-time {
|
||
font-size: 0.8rem;
|
||
color: #999;
|
||
margin-top: 0.3rem;
|
||
}
|
||
|
||
.stats-card.total {
|
||
background: #fff7e6;
|
||
border: 1px solid #ffe7ba;
|
||
}
|
||
|
||
.stats-card.total h3 {
|
||
color: #d46b08;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<div id="messageContainer" class="message-container"></div>
|
||
|
||
<div class="header">
|
||
<div class="header-title">
|
||
<h1>网易大神审核数据监控看板</h1>
|
||
<span id="version-display" class="version-display">加载中...</span>
|
||
</div>
|
||
<div class="header-buttons">
|
||
<button class="current-user">当前登录用户:{{ username }}({{ staff_name }})</button>
|
||
<button class="refresh-button">刷新数据</button>
|
||
<button class="check-now-button">更新当前小时数据</button>
|
||
<button class="test-alarm-button">测试告警</button>
|
||
<button class="restart-button">更新全天数据</button>
|
||
<button class="check-version-button">检测版本更新</button>
|
||
<button class="cms-settings-button">CMS系数设置</button>
|
||
<button class="breeze-settings-button">Breeze系数设置</button>
|
||
<button id="logout-button">登出</button>
|
||
</div>
|
||
</div>
|
||
<div class="stats-container">
|
||
<div class="stats-card">
|
||
<h3>清风审核</h3>
|
||
<div class="stats-row">
|
||
<div class="stats-item">
|
||
<span class="stats-label">当前小时</span>
|
||
<span class="stats-value" id="breeze-total">0</span>
|
||
<span class="stats-time" id="breeze-hourly-time">-</span>
|
||
</div>
|
||
<div class="stats-item">
|
||
<span class="stats-label">今日累计</span>
|
||
<span class="stats-value" id="breeze-daily-total">0</span>
|
||
<span class="stats-time" id="breeze-daily-time">-</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stats-card">
|
||
<h3>大神CMS</h3>
|
||
<div class="stats-row">
|
||
<div class="stats-item">
|
||
<span class="stats-label">当前小时</span>
|
||
<span class="stats-value" id="cms-total">0</span>
|
||
<span class="stats-time" id="cms-hourly-time">-</span>
|
||
</div>
|
||
<div class="stats-item">
|
||
<span class="stats-label">今日累计</span>
|
||
<span class="stats-value" id="cms-daily-total">0</span>
|
||
<span class="stats-time" id="cms-daily-time">-</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stats-card">
|
||
<h3>CC审核平台-论坛审核</h3>
|
||
<div class="stats-row">
|
||
<div class="stats-item">
|
||
<span class="stats-label">当前小时</span>
|
||
<div class="stats-value">
|
||
<span id="inspect-hourly-total">0</span>
|
||
<span class="weighted-number" id="inspect-hourly-weighted">(0)</span>
|
||
</div>
|
||
<span class="stats-time" id="inspect-hourly-time">-</span>
|
||
</div>
|
||
<div class="stats-item">
|
||
<span class="stats-label">今日累计</span>
|
||
<div class="stats-value">
|
||
<span id="inspect-daily-total">0</span>
|
||
<span class="weighted-number" id="inspect-daily-weighted">(0)</span>
|
||
</div>
|
||
<span class="stats-time" id="inspect-daily-time">-</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stats-card total">
|
||
<h3>总计(折算量)</h3>
|
||
<div class="stats-row">
|
||
<div class="stats-item">
|
||
<span class="stats-label">当前小时</span>
|
||
<span class="stats-value" id="total-weighted-hourly">0</span>
|
||
<span class="stats-time" id="total-hourly-time">-</span>
|
||
</div>
|
||
<div class="stats-item">
|
||
<span class="stats-label">今日累计</span>
|
||
<span class="stats-value" id="total-weighted-daily">0</span>
|
||
<span class="stats-time" id="total-daily-time">-</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 存储告警阈值的隐藏元素 -->
|
||
<div id="alarm-threshold" style="display:none"></div>
|
||
|
||
<div id="alarm-banner" class="alarm-banner">
|
||
<div class="alarm-message">
|
||
<span id="alarm-type"></span>:当前小时折算总量已超过阈值<span id="alarm-details"></span>!
|
||
</div>
|
||
<button id="reset-alarm" class="alarm-button">知道了</button>
|
||
</div>
|
||
|
||
<div class="container">
|
||
<div class="panel">
|
||
<div class="panel-header">
|
||
<h2>清风审核</h2>
|
||
<div class="last-update" id="breeze-last-update">最后更新: 暂无</div>
|
||
</div>
|
||
<div class="panel-body">
|
||
<div class="data-section">
|
||
<h3>当前小时数据</h3>
|
||
<div class="data-card">
|
||
<div class="value" id="breeze-hourly-count">-</div>
|
||
<div class="label">工单总数</div>
|
||
</div>
|
||
<div class="data-total">
|
||
<div class="label">折算总计</div>
|
||
<div class="value" id="breeze-hourly-weighted">-</div>
|
||
</div>
|
||
<div class="categories" id="breeze-hourly-categories">
|
||
<div class="loading">加载中...</div>
|
||
</div>
|
||
</div>
|
||
<div class="data-section">
|
||
<h3>今日全天数据</h3>
|
||
<div class="data-card">
|
||
<div class="value" id="breeze-daily-count">-</div>
|
||
<div class="label">工单总数</div>
|
||
</div>
|
||
<div class="data-total">
|
||
<div class="label">折算总计</div>
|
||
<div class="value" id="breeze-daily-weighted">-</div>
|
||
</div>
|
||
<div class="categories" id="breeze-daily-categories">
|
||
<div class="loading">加载中...</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="panel">
|
||
<div class="panel-header">
|
||
<h2>大神CMS</h2>
|
||
<div class="last-update" id="cms-last-update">最后更新: 暂无</div>
|
||
</div>
|
||
<div class="panel-body">
|
||
<div class="data-section">
|
||
<h3>当前小时数据</h3>
|
||
<div class="data-grid">
|
||
<div class="data-card">
|
||
<div class="value" id="cms-hourly-comment">-</div>
|
||
<div class="label">评论</div>
|
||
<div class="data-coefficient" id="cms-hourly-coefficient-comment">系数: -</div>
|
||
</div>
|
||
<div class="data-card">
|
||
<div class="value" id="cms-hourly-feed">-</div>
|
||
<div class="label">动态</div>
|
||
<div class="data-coefficient" id="cms-hourly-coefficient-feed">系数: -</div>
|
||
</div>
|
||
<div class="data-card">
|
||
<div class="value" id="cms-hourly-complaint">-</div>
|
||
<div class="label">举报处理</div>
|
||
<div class="data-coefficient" id="cms-hourly-coefficient-complaint">系数: -</div>
|
||
</div>
|
||
<div class="data-card">
|
||
<div class="value" id="cms-hourly-count">-</div>
|
||
<div class="label">总记录数</div>
|
||
</div>
|
||
</div>
|
||
<div class="data-total">
|
||
<div class="label">折算总计</div>
|
||
<div class="value" id="cms-hourly-weighted">-</div>
|
||
</div>
|
||
</div>
|
||
<div class="data-section">
|
||
<h3>今日全天数据</h3>
|
||
<div class="data-grid">
|
||
<div class="data-card">
|
||
<div class="value" id="cms-daily-comment">-</div>
|
||
<div class="label">评论</div>
|
||
<div class="data-coefficient" id="cms-daily-coefficient-comment">系数: -</div>
|
||
</div>
|
||
<div class="data-card">
|
||
<div class="value" id="cms-daily-feed">-</div>
|
||
<div class="label">动态</div>
|
||
<div class="data-coefficient" id="cms-daily-coefficient-feed">系数: -</div>
|
||
</div>
|
||
<div class="data-card">
|
||
<div class="value" id="cms-daily-complaint">-</div>
|
||
<div class="label">举报处理</div>
|
||
<div class="data-coefficient" id="cms-daily-coefficient-complaint">系数: -</div>
|
||
</div>
|
||
<div class="data-card">
|
||
<div class="value" id="cms-daily-count">-</div>
|
||
<div class="label">总记录数</div>
|
||
</div>
|
||
</div>
|
||
<div class="data-total">
|
||
<div class="label">折算总计</div>
|
||
<div class="value" id="cms-daily-weighted">-</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CMS系数设置对话框 -->
|
||
<div id="settings-dialog" class="dialog">
|
||
<div class="dialog-content">
|
||
<span class="close" onclick="document.getElementById('settings-dialog').style.display='none'">×</span>
|
||
<h2>CMS系数设置</h2>
|
||
<div class="settings-form">
|
||
<div class="form-group">
|
||
<label for="cms-coefficient-comment">评论系数:</label>
|
||
<input type="number" id="cms-coefficient-comment" step="0.01" min="0" max="100" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="cms-coefficient-feed">动态系数:</label>
|
||
<input type="number" id="cms-coefficient-feed" step="0.01" min="0" max="100" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="cms-coefficient-complaint">举报系数:</label>
|
||
<input type="number" id="cms-coefficient-complaint" step="0.01" min="0" max="100" />
|
||
</div>
|
||
<button id="save-settings-button">保存</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Breeze系数设置对话框 -->
|
||
<div id="breeze-settings-dialog" class="dialog">
|
||
<div class="dialog-content">
|
||
<span class="close"
|
||
onclick="document.getElementById('breeze-settings-dialog').style.display='none'">×</span>
|
||
<h2>Breeze系数设置</h2>
|
||
<div class="settings-form" id="breeze-settings-form">
|
||
<!-- 系数输入字段将在JS中动态生成 -->
|
||
<div class="form-group loading">
|
||
<p>正在加载系数数据...</p>
|
||
</div>
|
||
<button id="save-breeze-settings-button">保存</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 版本更新通知弹窗 -->
|
||
<div id="versionDialog" class="dialog">
|
||
<div class="dialog-content">
|
||
<span class="close" onclick="document.getElementById('versionDialog').style.display='none'">×</span>
|
||
<h2 id="versionDialogTitle">系统版本检测</h2>
|
||
<div class="version-info">
|
||
<p>当前版本: <span id="currentVersion">-</span></p>
|
||
<p>最新版本: <span id="onlineVersion">-</span></p>
|
||
<p id="versionStatus"></p>
|
||
<p class="check-time">上次检查: <span id="lastCheckTime">-</span></p>
|
||
</div>
|
||
<div style="display: flex; justify-content: flex-end;">
|
||
<button id="updateButton" class="dialog-button update" style="display: none;">立即更新</button>
|
||
<button id="close-version-dialog" class="dialog-button">关闭</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 无法识别工单弹窗 -->
|
||
<div id="unrecognizedIssuesDialog" class="dialog">
|
||
<div class="dialog-content">
|
||
<span class="close" onclick="document.getElementById('unrecognizedIssuesDialog').style.display='none'">×</span>
|
||
<h2>无法识别的工单</h2>
|
||
<div class="unrecognized-issues-list" style="max-height: 400px; overflow-y: auto;">
|
||
<div class="loading">加载中...</div>
|
||
</div>
|
||
<button class="dialog-button" onclick="document.getElementById('unrecognizedIssuesDialog').style.display='none'">关闭</button>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// 建立 WebSocket 连接
|
||
const socket = io();
|
||
|
||
// 监听模板文件变更事件
|
||
socket.on('template_changed', function(data) {
|
||
console.log('模板文件已更新:', data.file);
|
||
// 刷新页面
|
||
window.location.reload();
|
||
});
|
||
|
||
// 定义全局变量
|
||
let settingsDialog;
|
||
let breezeSettingsDialog;
|
||
let alarmBanner;
|
||
let alarmsInterval = null;
|
||
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
// 初始化变量
|
||
settingsDialog = document.getElementById('settings-dialog');
|
||
breezeSettingsDialog = document.getElementById('breeze-settings-dialog');
|
||
alarmBanner = document.getElementById('alarm-banner');
|
||
|
||
// 绑定所有按钮事件
|
||
bindEvents();
|
||
|
||
// 获取版本信息并检查更新
|
||
fetch('/api/get-version')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// 显示时间戳版本和固定版本号
|
||
document.getElementById('version-display').textContent = data.data.current_version || 'v1.0.0';
|
||
|
||
// 如果有更新,自动显示版本检测对话框
|
||
if (data.data.has_update) {
|
||
document.getElementById('currentVersion').textContent = data.data.current_version || '-';
|
||
document.getElementById('onlineVersion').textContent = data.data.online_version || '-';
|
||
document.getElementById('lastCheckTime').textContent = data.data.last_check_time || '-';
|
||
document.getElementById('versionStatus').textContent = '有新版本可用!请更新系统以获得最新功能和修复。';
|
||
document.getElementById('updateButton').style.display = 'inline-block';
|
||
document.getElementById('versionDialog').style.display = 'block';
|
||
document.getElementById('versionDialogTitle').textContent = '检测到新版本更新';
|
||
}
|
||
}
|
||
})
|
||
.catch(console.error);
|
||
|
||
// 立即获取统计数据
|
||
fetchStats();
|
||
|
||
// 每 5 秒自动刷新一次数据
|
||
setInterval(fetchStats, 5000);
|
||
|
||
// 每 1 分钟检查一次告警状态
|
||
setInterval(checkAlarmStatus, 60000);
|
||
|
||
// 每 2 分钟刷新一次系数
|
||
setInterval(loadCoefficients, 120000);
|
||
|
||
// 初始检查告警状态
|
||
checkAlarmStatus();
|
||
|
||
// 加载系数
|
||
loadCoefficients();
|
||
|
||
// 初始化检查每日数据按钮
|
||
document.getElementById('check-daily-btn').addEventListener('click', function () {
|
||
checkCmsDaily();
|
||
});
|
||
|
||
// 修改按钮文本
|
||
document.querySelector('.check-now-button').textContent = '更新当前小时数据';
|
||
document.querySelector('.restart-button').textContent = '更新全天数据';
|
||
|
||
// 修改按钮事件绑定
|
||
document.querySelector('.check-now-button').addEventListener('click', function() {
|
||
if (confirm('确认要更新当前小时数据吗?')) {
|
||
checkNow();
|
||
}
|
||
});
|
||
|
||
document.querySelector('.restart-button').addEventListener('click', function() {
|
||
if (confirm('确认要更新全天数据吗?')) {
|
||
checkDaily();
|
||
}
|
||
});
|
||
});
|
||
|
||
// 获取统计数据
|
||
function fetchStats() {
|
||
fetch('/api/get-stats')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
updateDashboard(data.data);
|
||
|
||
// 如果数据中包含系数,更新系数显示
|
||
if (data.data.cms && data.data.cms.coefficients) {
|
||
updateCoefficientsDisplay(data.data.cms.coefficients);
|
||
}
|
||
} else {
|
||
console.error('获取数据失败:', data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('获取数据出错:', error);
|
||
});
|
||
}
|
||
|
||
// 检查告警状态
|
||
function checkAlarmStatus() {
|
||
fetch('/api/get-alarm-status')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success && data.data.is_alarming) {
|
||
alarmBanner.classList.add('active');
|
||
|
||
// 从API返回数据中获取告警类型
|
||
const alarmType = data.data.alarm_type || "实时告警";
|
||
document.getElementById('alarm-type').textContent = alarmType;
|
||
|
||
// 更新告警详细信息
|
||
const total = parseFloat(document.getElementById('total-weighted-hourly').textContent);
|
||
const threshold = data.data.threshold;
|
||
if (!isNaN(total) && total > 0) {
|
||
const overPercentage = ((total - threshold) / threshold * 100).toFixed(1);
|
||
document.getElementById('alarm-details').textContent = ` (当前值:${total},超出${overPercentage}%)`;
|
||
}
|
||
} else {
|
||
alarmBanner.classList.remove('active');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('检查告警状态出错:', error);
|
||
});
|
||
}
|
||
|
||
// 更新仪表盘
|
||
function updateDashboard(data) {
|
||
try {
|
||
// 更新统计栏数据
|
||
if (data.breeze && data.breeze.hourly) {
|
||
// 更新顶部统计数据
|
||
document.getElementById('breeze-total').textContent = data.breeze.hourly.total || '0';
|
||
document.getElementById('breeze-daily-total').textContent = data.breeze.daily ? (data.breeze.daily.total || '0') : '0';
|
||
|
||
// 更新Breeze工单系统面板
|
||
document.getElementById('breeze-hourly-count').textContent = data.breeze.hourly.total || '-';
|
||
document.getElementById('breeze-hourly-weighted').textContent = data.breeze.hourly.weighted_total ? data.breeze.hourly.weighted_total.toFixed(2) : '-';
|
||
document.getElementById('breeze-daily-count').textContent = data.breeze.daily ? (data.breeze.daily.total || '-') : '-';
|
||
document.getElementById('breeze-daily-weighted').textContent = data.breeze.daily ? (data.breeze.daily.weighted_total || '-').toFixed(2) : '-';
|
||
|
||
// 更新小时类别数据
|
||
const breezeHourlyCategories = document.getElementById('breeze-hourly-categories');
|
||
if (data.breeze.hourly.categories) {
|
||
let categoriesHTML = `
|
||
<div class="category-header">
|
||
<div class="name">类别</div>
|
||
<div class="count">数量</div>
|
||
<div class="weighted">折算值</div>
|
||
</div>`;
|
||
for (const [name, info] of Object.entries(data.breeze.hourly.categories)) {
|
||
if (info.count > 0) {
|
||
categoriesHTML += `
|
||
<div class="category-item">
|
||
<div class="name">
|
||
${name}
|
||
<div style="font-size: 12px; color: #999;">系数: ${info.coefficient.toFixed(2)}</div>
|
||
</div>
|
||
<div class="count">${info.count}</div>
|
||
<div class="weighted">${info.weighted.toFixed(2)}</div>
|
||
</div>`;
|
||
}
|
||
}
|
||
breezeHourlyCategories.innerHTML = categoriesHTML || '<div class="loading">暂无数据</div>';
|
||
} else {
|
||
breezeHourlyCategories.innerHTML = '<div class="loading">暂无可用数据</div>';
|
||
}
|
||
|
||
// 更新日类别数据
|
||
const breezeDailyCategories = document.getElementById('breeze-daily-categories');
|
||
if (data.breeze.daily.categories) {
|
||
let categoriesHTML = `
|
||
<div class="category-header">
|
||
<div class="name">类别</div>
|
||
<div class="count">数量</div>
|
||
<div class="weighted">折算值</div>
|
||
</div>`;
|
||
for (const [name, info] of Object.entries(data.breeze.daily.categories)) {
|
||
if (info.count > 0) {
|
||
categoriesHTML += `
|
||
<div class="category-item">
|
||
<div class="name">
|
||
${name}
|
||
<div style="font-size: 12px; color: #999;">系数: ${info.coefficient.toFixed(2)}</div>
|
||
</div>
|
||
<div class="count">${info.count}</div>
|
||
<div class="weighted">${info.weighted.toFixed(2)}</div>
|
||
</div>`;
|
||
}
|
||
}
|
||
breezeDailyCategories.innerHTML = categoriesHTML || '<div class="loading">暂无数据</div>';
|
||
} else {
|
||
breezeDailyCategories.innerHTML = '<div class="loading">暂无可用数据</div>';
|
||
}
|
||
|
||
// 更新最后更新时间
|
||
document.getElementById('breeze-last-update').textContent = '最后更新: ' + data.breeze.hourly_update;
|
||
|
||
// 更新时间戳
|
||
if (data.breeze.hourly_update) {
|
||
document.getElementById('breeze-hourly-time').textContent = data.breeze.hourly_update;
|
||
}
|
||
if (data.breeze.daily_update) {
|
||
document.getElementById('breeze-daily-time').textContent = data.breeze.daily_update;
|
||
}
|
||
}
|
||
|
||
// 更新CMS数据
|
||
if (data.cms && data.cms.hourly) {
|
||
// 更新顶部统计栏
|
||
const cmsTotal = data.cms.hourly.total_count || 0;
|
||
document.getElementById('cms-total').textContent = cmsTotal;
|
||
document.getElementById('cms-daily-total').textContent = data.cms.daily ? (data.cms.daily.total_count || '0') : '0';
|
||
|
||
// 更新CMS审核系统面板
|
||
document.getElementById('cms-hourly-comment').textContent = data.cms.hourly.stats ? data.cms.hourly.stats.comment : '-';
|
||
document.getElementById('cms-hourly-feed').textContent = data.cms.hourly.stats ? data.cms.hourly.stats.feed : '-';
|
||
document.getElementById('cms-hourly-complaint').textContent = data.cms.hourly.stats ? data.cms.hourly.stats.complaint : '-';
|
||
document.getElementById('cms-hourly-count').textContent = data.cms.hourly.total_count || '-';
|
||
document.getElementById('cms-hourly-weighted').textContent = data.cms.hourly.weighted_total ? data.cms.hourly.weighted_total.toFixed(2) : '-';
|
||
document.getElementById('cms-last-update').textContent = '最后更新: ' + data.cms.hourly_update;
|
||
|
||
// 更新时间戳
|
||
if (data.cms.hourly_update) {
|
||
document.getElementById('cms-hourly-time').textContent = data.cms.hourly_update;
|
||
}
|
||
if (data.cms.daily_update) {
|
||
document.getElementById('cms-daily-time').textContent = data.cms.daily_update;
|
||
}
|
||
}
|
||
|
||
// 更新CMS每日数据
|
||
if (data.cms && data.cms.daily && data.cms.daily.stats) {
|
||
document.getElementById('cms-daily-comment').textContent = data.cms.daily.stats.comment || '-';
|
||
document.getElementById('cms-daily-feed').textContent = data.cms.daily.stats.feed || '-';
|
||
document.getElementById('cms-daily-complaint').textContent = data.cms.daily.stats.complaint || '-';
|
||
document.getElementById('cms-daily-count').textContent = data.cms.daily.total_count || '-';
|
||
document.getElementById('cms-daily-weighted').textContent = data.cms.daily.weighted_total ? data.cms.daily.weighted_total.toFixed(2) : '-';
|
||
}
|
||
|
||
// 更新CC审核平台数据
|
||
if (data.inspect && data.inspect.hourly) {
|
||
const hourlyTotal = data.inspect.hourly.total || 0;
|
||
const hourlyWeighted = data.inspect.hourly.weighted_total || 0;
|
||
document.getElementById('inspect-hourly-total').textContent = hourlyTotal;
|
||
document.getElementById('inspect-hourly-weighted').textContent = `(${Math.round(hourlyWeighted)})`;
|
||
document.getElementById('inspect-daily-total').textContent = data.inspect.daily ? (data.inspect.daily.total || '0') : '0';
|
||
if (data.inspect.daily) {
|
||
document.getElementById('inspect-daily-weighted').textContent = `(${Math.round(data.inspect.daily.weighted_total)})`;
|
||
}
|
||
|
||
// 更新时间戳
|
||
if (data.inspect.hourly_update) {
|
||
document.getElementById('inspect-hourly-time').textContent = data.inspect.hourly_update;
|
||
}
|
||
if (data.inspect.daily_update) {
|
||
document.getElementById('inspect-daily-time').textContent = data.inspect.daily_update;
|
||
}
|
||
}
|
||
|
||
// 更新总计数据
|
||
if (data.total) {
|
||
document.getElementById('total-weighted-hourly').textContent = Math.round(data.total.hourly);
|
||
document.getElementById('total-weighted-daily').textContent = Math.round(data.total.daily);
|
||
|
||
// 获取最新的时间戳
|
||
const hourlyUpdateTime = getLatestTimestamp([
|
||
data.breeze?.hourly_update,
|
||
data.cms?.hourly_update,
|
||
data.inspect?.hourly_update
|
||
]);
|
||
|
||
const dailyUpdateTime = getLatestTimestamp([
|
||
data.breeze?.daily_update,
|
||
data.cms?.daily_update,
|
||
data.inspect?.daily_update
|
||
]);
|
||
|
||
// 更新时间戳显示
|
||
if (hourlyUpdateTime) {
|
||
document.getElementById('total-hourly-time').textContent = hourlyUpdateTime;
|
||
}
|
||
if (dailyUpdateTime) {
|
||
document.getElementById('total-daily-time').textContent = dailyUpdateTime;
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('Error updating stats:', error);
|
||
}
|
||
}
|
||
|
||
// 加载系数
|
||
function loadCoefficients() {
|
||
// 加载CMS系数
|
||
fetch('/api/get-coefficients')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
updateCoefficientsDisplay(data.data);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('获取CMS系数出错:', error);
|
||
});
|
||
}
|
||
|
||
// 更新系数显示
|
||
function updateCoefficientsDisplay(coefficients) {
|
||
// 更新CMS系数显示
|
||
document.getElementById('cms-hourly-coefficient-comment').textContent =
|
||
'系数: ' + (coefficients.comment || '-').toFixed(2);
|
||
document.getElementById('cms-hourly-coefficient-feed').textContent =
|
||
'系数: ' + (coefficients.feed || '-').toFixed(2);
|
||
document.getElementById('cms-hourly-coefficient-complaint').textContent =
|
||
'系数: ' + (coefficients.complaint || '-').toFixed(2);
|
||
|
||
document.getElementById('cms-daily-coefficient-comment').textContent =
|
||
'系数: ' + (coefficients.comment || '-').toFixed(2);
|
||
document.getElementById('cms-daily-coefficient-feed').textContent =
|
||
'系数: ' + (coefficients.feed || '-').toFixed(2);
|
||
document.getElementById('cms-daily-coefficient-complaint').textContent =
|
||
'系数: ' + (coefficients.complaint || '-').toFixed(2);
|
||
}
|
||
|
||
// 显示CMS系数设置对话框
|
||
function showCMSSettingsDialog() {
|
||
fetch('/api/get-coefficients')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
document.getElementById('cms-coefficient-comment').value = data.data.comment;
|
||
document.getElementById('cms-coefficient-feed').value = data.data.feed;
|
||
document.getElementById('cms-coefficient-complaint').value = data.data.complaint;
|
||
settingsDialog.style.display = 'block';
|
||
} else {
|
||
alert('获取系数失败: ' + data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('获取系数出错:', error);
|
||
alert('获取系数出错');
|
||
});
|
||
}
|
||
|
||
// 显示Breeze系数设置对话框
|
||
function showBreezeSettingsDialog() {
|
||
fetch('/api/get-breeze-coefficients')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
const breezeSettingsForm = document.getElementById('breeze-settings-form');
|
||
|
||
// 清空现有内容
|
||
breezeSettingsForm.innerHTML = '';
|
||
|
||
// 为每个系数创建输入字段
|
||
const coefficients = data.data;
|
||
const chineseNames = {
|
||
'NTES_GOD_IMAGES': '网易大神APP图片',
|
||
'NTES_GOD_VIDEOS': '网易大神APP视频',
|
||
'NTES_GOD_CHAT_IMAGES': '网易大神APP聊天图片',
|
||
'NTES_GOD_CHAT_VIDEOS': '网易大神APP聊天视频',
|
||
'NTES_DASONG': '大神大宋视频',
|
||
'SPIDER_VIDEO': '大神普通供给视频',
|
||
'SPIDER_VIDEO_SP': '大神高优供给视频',
|
||
'NTES_GOD_AI': '大神AI图片',
|
||
'NTES_GOD_TOP': '大神短视频',
|
||
'T_SPIDER_VIDEO': '大神tiktok普通视频',
|
||
'T_SPIDER_VIDEO_SP': '大神tiktok高优视频',
|
||
'V_SPIDER_VIDEO': '大神ins普通供给视频',
|
||
'V_SPIDER_VIDEO_SP': '大神ins高优供给视频',
|
||
'NTES_GOD_XHS': '大神小红书图片',
|
||
'XHS_SPIDER_VIDEO': '小红书供给视频',
|
||
'Cupid': '大神交友',
|
||
'CHAT_P2P': '大神聊天/风险用户_私聊/私聊频繁',
|
||
'CHAT_TEAM': '大神聊天/风险用户_群聊/群聊频繁',
|
||
'CHAT_ROOM': '大神聊天_聊天室',
|
||
'CHAT_ROOM_MSG': '风险用户_聊天室频繁'
|
||
};
|
||
|
||
// 创建搜索框
|
||
const searchDiv = document.createElement('div');
|
||
searchDiv.className = 'form-group search-group';
|
||
searchDiv.innerHTML = `
|
||
<label for="breeze-search">搜索系数:</label>
|
||
<input type="text" id="breeze-search" placeholder="输入关键词搜索系数" />
|
||
`;
|
||
breezeSettingsForm.appendChild(searchDiv);
|
||
|
||
// 创建表单内容容器
|
||
const formContentDiv = document.createElement('div');
|
||
formContentDiv.className = 'form-content';
|
||
breezeSettingsForm.appendChild(formContentDiv);
|
||
|
||
// 为每个系数创建输入字段
|
||
for (const [key, value] of Object.entries(coefficients)) {
|
||
const formGroup = document.createElement('div');
|
||
formGroup.className = 'form-group';
|
||
formGroup.dataset.name = key;
|
||
|
||
const label = document.createElement('label');
|
||
label.htmlFor = `breeze-coefficient-${key}`;
|
||
label.textContent = chineseNames[key] || key;
|
||
|
||
const input = document.createElement('input');
|
||
input.type = 'number';
|
||
input.id = `breeze-coefficient-${key}`;
|
||
input.className = 'breeze-coefficient';
|
||
input.dataset.key = key;
|
||
input.step = '0.01';
|
||
input.min = '0';
|
||
input.max = '200';
|
||
input.value = value;
|
||
|
||
formGroup.appendChild(label);
|
||
formGroup.appendChild(input);
|
||
formContentDiv.appendChild(formGroup);
|
||
}
|
||
|
||
// 添加搜索功能
|
||
const searchInput = document.getElementById('breeze-search');
|
||
searchInput.addEventListener('input', function () {
|
||
const searchText = this.value.toLowerCase();
|
||
const formGroups = formContentDiv.querySelectorAll('.form-group');
|
||
|
||
formGroups.forEach(group => {
|
||
const key = group.dataset.name;
|
||
const label = group.querySelector('label').textContent.toLowerCase();
|
||
|
||
if (key && key.toLowerCase().includes(searchText) || label.includes(searchText)) {
|
||
group.style.display = '';
|
||
} else {
|
||
group.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
// 添加保存按钮
|
||
const saveButton = document.createElement('button');
|
||
saveButton.id = 'save-breeze-settings-button';
|
||
saveButton.textContent = '保存';
|
||
saveButton.addEventListener('click', saveBreezeCoefficients);
|
||
breezeSettingsForm.appendChild(saveButton);
|
||
|
||
// 显示对话框
|
||
breezeSettingsDialog.style.display = 'block';
|
||
} else {
|
||
alert('获取Breeze系数失败: ' + data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('获取Breeze系数出错:', error);
|
||
alert('获取Breeze系数出错');
|
||
});
|
||
}
|
||
|
||
// 保存Breeze系数设置
|
||
function saveBreezeCoefficients() {
|
||
const coefficientInputs = document.querySelectorAll('.breeze-coefficient');
|
||
const newCoefficients = {};
|
||
|
||
coefficientInputs.forEach(input => {
|
||
if (input.value) {
|
||
newCoefficients[input.dataset.key] = parseFloat(input.value);
|
||
}
|
||
});
|
||
|
||
fetch('/api/update-breeze-coefficients', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(newCoefficients)
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
alert('Breeze系数更新成功');
|
||
breezeSettingsDialog.style.display = 'none';
|
||
|
||
// 刷新数据
|
||
setTimeout(fetchStats, 2000);
|
||
} else {
|
||
alert('更新Breeze系数失败: ' + data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('更新Breeze系数出错:', error);
|
||
alert('更新Breeze系数出错');
|
||
});
|
||
}
|
||
|
||
// 绑定按钮事件
|
||
function bindEvents() {
|
||
// 绑定刷新数据按钮事件
|
||
document.querySelector('.refresh-button').addEventListener('click', fetchStats);
|
||
|
||
// 绑定立即检查按钮事件
|
||
document.querySelector('.check-now-button').addEventListener('click', checkNow);
|
||
|
||
// 绑定测试告警按钮事件
|
||
document.querySelector('.test-alarm-button').addEventListener('click', testAlarm);
|
||
|
||
// 绑定重启监控按钮事件
|
||
document.querySelector('.restart-button').addEventListener('click', restartMonitor);
|
||
|
||
// 绑定版本检测更新按钮事件
|
||
document.querySelector('.check-version-button').addEventListener('click', checkVersion);
|
||
|
||
// 绑定CMS系数设置按钮事件
|
||
document.querySelector('.cms-settings-button').addEventListener('click', showCMSSettingsDialog);
|
||
|
||
// 绑定Breeze系数设置按钮事件
|
||
document.querySelector('.breeze-settings-button').addEventListener('click', showBreezeSettingsDialog);
|
||
|
||
// 绑定登出按钮事件
|
||
document.getElementById('logout-button').addEventListener('click', function () {
|
||
if (confirm('确认要登出吗?')) {
|
||
window.location.href = '/logout';
|
||
}
|
||
});
|
||
|
||
// 绑定版本对话框的关闭按钮事件
|
||
document.getElementById('close-version-dialog').addEventListener('click', function() {
|
||
document.getElementById('versionDialog').style.display = 'none';
|
||
});
|
||
|
||
// 绑定版本更新按钮事件
|
||
document.getElementById('updateButton').addEventListener('click', handleVersionUpdate);
|
||
|
||
// 绑定告警确认按钮事件
|
||
document.getElementById('reset-alarm').addEventListener('click', function () {
|
||
acknowledgeAlarm();
|
||
});
|
||
}
|
||
|
||
// 立即检查当前小时数据
|
||
function checkNow() {
|
||
// 禁用按钮,显示加载状态
|
||
const checkNowButton = document.querySelector('.check-now-button');
|
||
if (checkNowButton) {
|
||
checkNowButton.disabled = true;
|
||
checkNowButton.textContent = '正在更新...';
|
||
checkNowButton.style.opacity = '0.5';
|
||
checkNowButton.style.cursor = 'not-allowed';
|
||
}
|
||
|
||
fetch('/api/check-now')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// 创建一个通知元素
|
||
const notification = document.createElement('div');
|
||
notification.className = 'check-notification';
|
||
notification.style.position = 'fixed';
|
||
notification.style.top = '50%';
|
||
notification.style.left = '50%';
|
||
notification.style.transform = 'translate(-50%, -50%)';
|
||
notification.style.padding = '20px';
|
||
notification.style.backgroundColor = '#2196F3';
|
||
notification.style.color = 'white';
|
||
notification.style.borderRadius = '8px';
|
||
notification.style.boxShadow = '0 4px 12px rgba(0,0,0,0.2)';
|
||
notification.style.zIndex = '9999';
|
||
notification.style.textAlign = 'center';
|
||
notification.style.maxWidth = '80%';
|
||
notification.innerHTML = `
|
||
<h3 style="margin-top:0;">数据更新进行中</h3>
|
||
<p>系统正在获取最新数据,请耐心等待...</p>
|
||
<div class="progress-bar" style="height:5px;background:#1565C0;width:0%;margin:10px 0;border-radius:3px;"></div>
|
||
<p style="font-size:0.9em;">更新过程需要10-30秒,请勿频繁点击检查按钮</p>
|
||
`;
|
||
document.body.appendChild(notification);
|
||
|
||
// 开始进度条动画
|
||
let progress = 0;
|
||
const progressBar = notification.querySelector('.progress-bar');
|
||
const progressInterval = setInterval(() => {
|
||
progress += 2;
|
||
if (progress <= 100) {
|
||
progressBar.style.width = `${progress}%`;
|
||
} else {
|
||
clearInterval(progressInterval);
|
||
}
|
||
}, 300);
|
||
|
||
// 5秒后刷新数据(此时数据可能还未更新完成)
|
||
setTimeout(fetchStats, 5000);
|
||
|
||
// 15秒后再次刷新(确保获取更新后的数据)
|
||
setTimeout(fetchStats, 15000);
|
||
|
||
// 20秒后移除通知并恢复按钮
|
||
setTimeout(() => {
|
||
document.body.removeChild(notification);
|
||
clearInterval(progressInterval);
|
||
|
||
// 恢复按钮状态
|
||
if (checkNowButton) {
|
||
checkNowButton.disabled = false;
|
||
checkNowButton.textContent = '更新当前小时数据';
|
||
checkNowButton.style.opacity = '1';
|
||
checkNowButton.style.cursor = 'pointer';
|
||
}
|
||
}, 20000);
|
||
} else {
|
||
alert('数据更新失败: ' + data.message);
|
||
|
||
// 恢复按钮状态
|
||
if (checkNowButton) {
|
||
checkNowButton.disabled = false;
|
||
checkNowButton.textContent = '更新当前小时数据';
|
||
checkNowButton.style.opacity = '1';
|
||
checkNowButton.style.cursor = 'pointer';
|
||
}
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('数据更新出错,请查看控制台日志:', error);
|
||
alert('数据更新出错,请查看控制台日志');
|
||
|
||
// 恢复按钮状态
|
||
if (checkNowButton) {
|
||
checkNowButton.disabled = false;
|
||
checkNowButton.textContent = '更新当前小时数据';
|
||
checkNowButton.style.opacity = '1';
|
||
checkNowButton.style.cursor = 'pointer';
|
||
}
|
||
});
|
||
}
|
||
|
||
// 重启监控进程
|
||
function restartMonitor() {
|
||
if (!confirm('确认要立即更新全天数据吗?')) {
|
||
return;
|
||
}
|
||
|
||
fetch('/api/restart-monitoring')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
alert('全天数据正在更新,稍后将更新数据');
|
||
|
||
// 5秒后刷新数据
|
||
setTimeout(fetchStats, 5000);
|
||
} else {
|
||
alert('重启失败: ' + data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('数据更新出错,请查看控制台日志:', error);
|
||
alert('数据更新出错,请查看控制台日志');
|
||
});
|
||
}
|
||
|
||
// 测试告警功能
|
||
function testAlarm() {
|
||
if (!confirm('确认要测试告警功能吗?这将触发一次测试告警通知。')) {
|
||
return;
|
||
}
|
||
|
||
fetch('/api/test-alarm')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// 测试告警成功,不需要额外提示
|
||
console.log('测试告警已触发');
|
||
} else {
|
||
alert('测试告警失败: ' + data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('测试告警出错:', error);
|
||
alert('测试告警出错');
|
||
});
|
||
}
|
||
|
||
// 确认并重置告警
|
||
function acknowledgeAlarm() {
|
||
fetch('/api/acknowledge-alarm')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// 强制移除告警横幅显示,不管是什么类型的告警
|
||
document.getElementById('alarm-banner').classList.remove('active');
|
||
console.log('告警已确认并重置');
|
||
} else {
|
||
alert('确认告警失败: ' + data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('确认告警出错:', error);
|
||
alert('确认告警出错');
|
||
// 即使出错也尝试移除告警横幅
|
||
document.getElementById('alarm-banner').classList.remove('active');
|
||
});
|
||
}
|
||
|
||
// 版本更新处理函数
|
||
function handleVersionUpdate() {
|
||
// 显示确认对话框
|
||
if (confirm('确认要更新系统吗?这将会关闭当前系统并自动下载安装最新版本。')) {
|
||
// 1. 先登出系统
|
||
fetch('/logout')
|
||
.then(response => {
|
||
if (response.ok) {
|
||
// 2. 调用更新API
|
||
return fetch('/api/update-system', {
|
||
method: 'POST'
|
||
});
|
||
}
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
alert('更新程序已启动,系统即将关闭。');
|
||
// 关闭当前窗口
|
||
window.close();
|
||
} else {
|
||
alert('更新失败:' + data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('更新失败:', error);
|
||
alert('系统更新失败,请稍后重试。');
|
||
});
|
||
}
|
||
}
|
||
|
||
// 检测版本更新
|
||
function checkVersion() {
|
||
// 显示加载中状态
|
||
const checkVersionButton = document.querySelector('.check-version-button');
|
||
if (checkVersionButton) {
|
||
checkVersionButton.disabled = true;
|
||
checkVersionButton.textContent = '检测中...';
|
||
checkVersionButton.style.opacity = '0.5';
|
||
checkVersionButton.style.cursor = 'not-allowed';
|
||
}
|
||
|
||
fetch('/api/check-version')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// 更新弹窗信息
|
||
document.getElementById('currentVersion').textContent = data.data.current_version || '-';
|
||
document.getElementById('onlineVersion').textContent = data.data.online_version || '-';
|
||
document.getElementById('lastCheckTime').textContent = data.data.last_check_time || '-';
|
||
|
||
// 更新标题中的版本号
|
||
document.getElementById('version-display').textContent = data.data.current_version || 'v1.0.0';
|
||
|
||
// 显示正确的状态信息和更新按钮
|
||
const updateButton = document.getElementById('updateButton');
|
||
if (data.data.has_update) {
|
||
document.getElementById('versionDialogTitle').textContent = '检测到新版本更新';
|
||
document.getElementById('versionStatus').textContent = '有新版本可用!请更新系统以获得最新功能和修复。';
|
||
updateButton.style.display = 'inline-block'; // 显示更新按钮
|
||
} else {
|
||
document.getElementById('versionDialogTitle').textContent = '系统版本检测';
|
||
document.getElementById('versionStatus').textContent = '您当前使用的是最新版本。';
|
||
updateButton.style.display = 'none'; // 隐藏更新按钮
|
||
}
|
||
|
||
// 显示弹窗
|
||
document.getElementById('versionDialog').style.display = 'block';
|
||
} else {
|
||
// 显示错误信息
|
||
document.getElementById('versionDialogTitle').textContent = '系统版本检测';
|
||
document.getElementById('versionStatus').textContent = data.message || '无法获取版本信息,请稍后再试。';
|
||
|
||
// 更新弹窗信息 - 即便出错也尝试显示当前版本
|
||
if (data.data && data.data.current_version) {
|
||
document.getElementById('currentVersion').textContent = data.data.current_version;
|
||
document.getElementById('version-display').textContent = data.data.current_version;
|
||
}
|
||
|
||
// 显示弹窗
|
||
document.getElementById('versionDialog').style.display = 'block';
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('检测版本出错:', error);
|
||
// 显示错误信息
|
||
document.getElementById('versionDialogTitle').textContent = '系统版本检测';
|
||
document.getElementById('versionStatus').textContent = '检测版本出错,请稍后再试。';
|
||
// 显示弹窗
|
||
document.getElementById('versionDialog').style.display = 'block';
|
||
})
|
||
.finally(() => {
|
||
// 恢复按钮状态
|
||
if (checkVersionButton) {
|
||
checkVersionButton.disabled = false;
|
||
checkVersionButton.textContent = '检测版本更新';
|
||
checkVersionButton.style.opacity = '1';
|
||
checkVersionButton.style.cursor = 'pointer';
|
||
}
|
||
});
|
||
}
|
||
|
||
// 立即检查CMS每日数据
|
||
function checkCmsDaily() {
|
||
// 显示加载状态
|
||
const dailyBtn = document.getElementById('check-daily-btn');
|
||
const originalText = dailyBtn.innerHTML;
|
||
dailyBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 检查中...';
|
||
dailyBtn.disabled = true;
|
||
|
||
fetch('/api/check-cms-daily', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
showNotification('检查成功', '已触发CMS每日数据检查,数据将在约一分钟内更新。', 'success');
|
||
|
||
// 30秒后刷新页面以展示更新后的数据
|
||
setTimeout(() => {
|
||
location.reload();
|
||
}, 30000);
|
||
} else {
|
||
showNotification('检查失败', data.message, 'error');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('检查CMS每日数据时出错:', error);
|
||
showNotification('检查失败', '请求发生错误,请查看控制台获取详情', 'error');
|
||
})
|
||
.finally(() => {
|
||
// 恢复按钮状态
|
||
setTimeout(() => {
|
||
dailyBtn.innerHTML = originalText;
|
||
dailyBtn.disabled = false;
|
||
}, 3000);
|
||
});
|
||
}
|
||
|
||
// 添加WebSocket监听代码
|
||
socket.on('version_update', function(data) {
|
||
if (data.type === 'show_version_dialog') {
|
||
// 更新对话框内容
|
||
document.getElementById('currentVersion').textContent = data.current_version;
|
||
document.getElementById('onlineVersion').textContent = data.online_version;
|
||
document.getElementById('versionDialogTitle').textContent = '检测到新版本更新';
|
||
document.getElementById('versionStatus').textContent = '有新版本可用!请更新系统以获得最新功能和修复。';
|
||
|
||
// 显示更新按钮
|
||
document.getElementById('updateButton').style.display = 'inline-block';
|
||
|
||
// 显示对话框
|
||
document.getElementById('versionDialog').style.display = 'block';
|
||
}
|
||
});
|
||
|
||
// 显示无法识别的工单
|
||
function showUnrecognizedIssues(issues) {
|
||
const dialog = document.getElementById('unrecognizedIssuesDialog');
|
||
const listContainer = dialog.querySelector('.unrecognized-issues-list');
|
||
|
||
let html = '<div class="issues-list">';
|
||
issues.forEach(issue => {
|
||
html += `
|
||
<div class="issue-item" style="margin-bottom: 10px; padding: 10px; border: 1px solid #ddd; border-radius: 4px;">
|
||
<div><strong>工单ID:</strong> ${issue.id}</div>
|
||
<div><strong>标题:</strong> ${issue.title}</div>
|
||
<div><strong>产品代码:</strong> ${issue.product || '未知'}</div>
|
||
<div><strong>时间:</strong> ${issue.time || '未知'}</div>
|
||
</div>
|
||
`;
|
||
});
|
||
html += '</div>';
|
||
|
||
listContainer.innerHTML = html;
|
||
dialog.style.display = 'block';
|
||
}
|
||
|
||
// 添加更新全天数据的函数
|
||
function checkDaily() {
|
||
const restartButton = document.querySelector('.restart-button');
|
||
if (restartButton) {
|
||
restartButton.disabled = true;
|
||
restartButton.textContent = '更新中...';
|
||
restartButton.style.opacity = '0.5';
|
||
restartButton.style.cursor = 'not-allowed';
|
||
}
|
||
|
||
fetch('/api/check-daily')
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
showNotification('更新成功', '全天数据更新已触发,请稍后查看结果。', 'success');
|
||
setTimeout(fetchStats, 5000);
|
||
} else {
|
||
showNotification('更新失败', data.message, 'error');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('更新全天数据出错:', error);
|
||
showNotification('更新失败', '请求发生错误,请查看控制台获取详情', 'error');
|
||
})
|
||
.finally(() => {
|
||
if (restartButton) {
|
||
setTimeout(() => {
|
||
restartButton.disabled = false;
|
||
restartButton.textContent = '更新全天数据';
|
||
restartButton.style.opacity = '1';
|
||
restartButton.style.cursor = 'pointer';
|
||
}, 3000);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 消息提示函数
|
||
function showMessage(type, content) {
|
||
const container = document.getElementById('messageContainer');
|
||
const message = document.createElement('div');
|
||
message.className = `message ${type}`;
|
||
message.textContent = content;
|
||
container.appendChild(message);
|
||
|
||
// 3秒后自动移除消息
|
||
setTimeout(() => {
|
||
message.addEventListener('animationend', () => {
|
||
container.removeChild(message);
|
||
});
|
||
}, 3000);
|
||
}
|
||
|
||
// 添加全局消息对象
|
||
window.message = {
|
||
success: (content) => showMessage('success', content),
|
||
info: (content) => showMessage('info', content),
|
||
error: (content) => showMessage('error', content)
|
||
};
|
||
|
||
// 在页面加载完成后检查是否需要显示欢迎消息
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const staff_name = localStorage.getItem('staff_name');
|
||
if (staff_name) {
|
||
showMessage('info', `你好,${staff_name}`);
|
||
localStorage.removeItem('staff_name'); // 清除,确保消息只显示一次
|
||
}
|
||
});
|
||
|
||
function updateStats(data) {
|
||
try {
|
||
// 更新统计栏数据
|
||
if (data.breeze && data.breeze.hourly) {
|
||
document.getElementById('breeze-total').textContent = data.breeze.hourly.total || '0';
|
||
document.getElementById('breeze-daily-total').textContent = data.breeze.daily ? (data.breeze.daily.total || '0') : '0';
|
||
|
||
// 更新时间戳
|
||
if (data.breeze.hourly_update) {
|
||
document.getElementById('breeze-hourly-time').textContent = data.breeze.hourly_update;
|
||
}
|
||
if (data.breeze.daily_update) {
|
||
document.getElementById('breeze-daily-time').textContent = data.breeze.daily_update;
|
||
}
|
||
}
|
||
|
||
// 更新CMS数据
|
||
if (data.cms && data.cms.hourly) {
|
||
// 更新顶部统计栏
|
||
const cmsTotal = data.cms.hourly.total_count || 0;
|
||
document.getElementById('cms-total').textContent = cmsTotal;
|
||
document.getElementById('cms-daily-total').textContent = data.cms.daily ? (data.cms.daily.total_count || '0') : '0';
|
||
|
||
// 更新时间戳
|
||
if (data.cms.hourly_update) {
|
||
document.getElementById('cms-hourly-time').textContent = data.cms.hourly_update;
|
||
}
|
||
if (data.cms.daily_update) {
|
||
document.getElementById('cms-daily-time').textContent = data.cms.daily_update;
|
||
}
|
||
}
|
||
|
||
// 更新CC审核平台数据
|
||
if (data.inspect && data.inspect.hourly) {
|
||
const hourlyTotal = data.inspect.hourly.total || 0;
|
||
const hourlyWeighted = data.inspect.hourly.weighted_total || 0;
|
||
document.getElementById('inspect-hourly-total').textContent = hourlyTotal;
|
||
document.getElementById('inspect-hourly-weighted').textContent = `(${Math.round(hourlyWeighted)})`;
|
||
document.getElementById('inspect-daily-total').textContent = data.inspect.daily ? (data.inspect.daily.total || '0') : '0';
|
||
if (data.inspect.daily) {
|
||
document.getElementById('inspect-daily-weighted').textContent = `(${Math.round(data.inspect.daily.weighted_total)})`;
|
||
}
|
||
|
||
// 更新时间戳
|
||
if (data.inspect.hourly_update) {
|
||
document.getElementById('inspect-hourly-time').textContent = data.inspect.hourly_update;
|
||
}
|
||
if (data.inspect.daily_update) {
|
||
document.getElementById('inspect-daily-time').textContent = data.inspect.daily_update;
|
||
}
|
||
}
|
||
|
||
// 更新总计数据
|
||
if (data.total) {
|
||
document.getElementById('total-weighted-hourly').textContent = Math.round(data.total.hourly);
|
||
document.getElementById('total-weighted-daily').textContent = Math.round(data.total.daily);
|
||
|
||
// 获取最新的时间戳
|
||
const hourlyUpdateTime = getLatestTimestamp([
|
||
data.breeze?.hourly_update,
|
||
data.cms?.hourly_update,
|
||
data.inspect?.hourly_update
|
||
]);
|
||
|
||
const dailyUpdateTime = getLatestTimestamp([
|
||
data.breeze?.daily_update,
|
||
data.cms?.daily_update,
|
||
data.inspect?.daily_update
|
||
]);
|
||
|
||
// 更新时间戳显示
|
||
if (hourlyUpdateTime) {
|
||
document.getElementById('total-hourly-time').textContent = hourlyUpdateTime;
|
||
}
|
||
if (dailyUpdateTime) {
|
||
document.getElementById('total-daily-time').textContent = dailyUpdateTime;
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('Error updating stats:', error);
|
||
}
|
||
}
|
||
|
||
function updateInspectStats(inspectData) {
|
||
if (inspectData.hourly) {
|
||
document.getElementById('inspect-hourly-total').textContent = inspectData.hourly.weighted_total.toFixed(2);
|
||
document.getElementById('inspect-hourly-time').textContent = formatTimestamp(inspectData.hourly_update);
|
||
}
|
||
}
|
||
|
||
// 添加一个辅助函数来获取最新的时间戳
|
||
function getLatestTimestamp(timestamps) {
|
||
const validTimestamps = timestamps.filter(t => t);
|
||
if (validTimestamps.length === 0) return null;
|
||
|
||
// 假设时间戳格式为 "YYYY-MM-DD HH:mm:ss"
|
||
return validTimestamps.reduce((latest, current) => {
|
||
if (!latest) return current;
|
||
return new Date(current) > new Date(latest) ? current : latest;
|
||
}, null);
|
||
}
|
||
</script>
|
||
</body>
|
||
|
||
</html> |