mirror of
https://github.com/WizisCool/Nezha-Traffic-Alarm-Generator.git
synced 2026-01-11 23:50:45 +08:00
Init
Init
This commit is contained in:
parent
77bdc3a5c9
commit
7c55ed0727
BIN
favicon.png
Normal file
BIN
favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
126
index.html
Normal file
126
index.html
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>哪吒面板流量警告规则生成器</title>
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/default.min.css">
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
<link rel="icon" href="./favicon.png">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container my-5">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h1 class="text-center">哪吒流量警告规则生成器</h1>
|
||||||
|
<div class="text-right">
|
||||||
|
<a href="https://dooo.ng" target="_blank" class="btn btn-outline-dark">
|
||||||
|
<i class="fa-solid fa-blog"></i> Doong博客
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/WizisCool/Nezha-Traffic-Alarm-Generator" target="_blank"
|
||||||
|
class="btn btn-outline-primary ml-2">
|
||||||
|
<i class="fab fa-github"></i> Give me a Star
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="serverIds">服务器 ID (用逗号分隔):</label>
|
||||||
|
<input type="text" class="form-control" id="serverIds" placeholder="例如: 1,2,3" value="0">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>统计周期开始时间:</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<select class="form-control" id="cycleStartTimezone"></select>
|
||||||
|
<input type="text" class="form-control" id="cycleStartDate" placeholder="可选择日期" data-input>
|
||||||
|
<input type="text" class="form-control" id="cycleStartTime" placeholder="可选择时间" data-input>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-control" id="cycleStart" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="trafficType">流量类型:</label>
|
||||||
|
<select class="form-control" id="trafficType">
|
||||||
|
<option value="transfer_in_cycle">入站流量</option>
|
||||||
|
<option value="transfer_out_cycle">出站流量</option>
|
||||||
|
<option value="transfer_all_cycle" selected>双向流量</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="cycleUnit">周期单位:</label>
|
||||||
|
<select class="form-control" id="cycleUnit">
|
||||||
|
<option value="hour">小时</option>
|
||||||
|
<option value="day">天</option>
|
||||||
|
<option value="week">周</option>
|
||||||
|
<option value="month" selected>月</option>
|
||||||
|
<option value="year">年</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="cycleInterval">周期间隔 (单位为选择的周期单位):</label>
|
||||||
|
<input type="number" class="form-control" id="cycleInterval" min="1" value="1">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="maxTraffic">流量上限:</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control" id="maxTraffic" min="0" value="1" step="0.01">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<select class="form-control" id="trafficUnit">
|
||||||
|
<option value="1024">KB</option>
|
||||||
|
<option value="1048576">MB</option>
|
||||||
|
<option value="1073741824" selected>GB</option>
|
||||||
|
<option value="1099511627776">TB</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary btn-block" id="generateRuleBtn">生成规则</button>
|
||||||
|
<div class="mt-4">
|
||||||
|
<label for="ruleOutput">生成的 JSON 规则:</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<pre class="form-control rule-output"><code id="ruleOutput" class="json"></code></pre>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button class="btn btn-secondary" type="button" id="copyRuleBtn">
|
||||||
|
<i class="fas fa-copy"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Modal -->
|
||||||
|
<div class="modal fade" id="errorModal" tabindex="-1" role="dialog" aria-labelledby="errorModalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="errorModalLabel">错误</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p id="errorMessage"></p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.33/moment-timezone-with-data.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/languages/json.min.js"></script>
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
156
script.js
Normal file
156
script.js
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
$(document).ready(function () {
|
||||||
|
// 获取所有时区
|
||||||
|
const allTimezones = moment.tz.names();
|
||||||
|
|
||||||
|
// 按 UTC 偏移量排序时区
|
||||||
|
allTimezones.sort((a, b) => {
|
||||||
|
const offsetA = moment.tz(a).utcOffset();
|
||||||
|
const offsetB = moment.tz(b).utcOffset();
|
||||||
|
return offsetA - offsetB;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 生成时区选项
|
||||||
|
const timezoneOptions = allTimezones.map(timezone => {
|
||||||
|
const offset = moment.tz(timezone).format('Z');
|
||||||
|
return `<option value="${timezone}">UTC${offset} ${timezone}</option>`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
|
||||||
|
$('#cycleStartTimezone').html(timezoneOptions);
|
||||||
|
|
||||||
|
// 设置默认时区为 UTC+8 上海时间
|
||||||
|
$('#cycleStartTimezone').val('Asia/Shanghai');
|
||||||
|
|
||||||
|
// 初始化日期选择器
|
||||||
|
const datePickr = flatpickr('#cycleStartDate', {
|
||||||
|
defaultDate: moment().startOf('month').toDate(),
|
||||||
|
dateFormat: 'Y-m-d',
|
||||||
|
onChange: updateCycleStart
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化时间选择器
|
||||||
|
const timePickr = flatpickr('#cycleStartTime', {
|
||||||
|
noCalendar: true,
|
||||||
|
enableTime: true,
|
||||||
|
dateFormat: 'H:i',
|
||||||
|
time_24hr: true,
|
||||||
|
defaultDate: '00:00',
|
||||||
|
onChange: updateCycleStart
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面加载时生成初始的 RFC3339 和 规则
|
||||||
|
updateCycleStart();
|
||||||
|
generateRule();
|
||||||
|
|
||||||
|
// 更新统计周期开始时间
|
||||||
|
function updateCycleStart() {
|
||||||
|
const timezone = $('#cycleStartTimezone').val();
|
||||||
|
const date = $('#cycleStartDate').val();
|
||||||
|
const time = $('#cycleStartTime').val();
|
||||||
|
const formattedDate = moment.tz(`${date} ${time}`, timezone).format();
|
||||||
|
$('#cycleStart').val(formattedDate);
|
||||||
|
generateRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防止用户编辑 RFC3339 格式时间
|
||||||
|
$('#cycleStart').on('input', function () {
|
||||||
|
showErrorModal('请使用上方的时间选择器选择时间');
|
||||||
|
$(this).val(moment.tz($('#cycleStartDate').val() + ' ' + $('#cycleStartTime').val(), $('#cycleStartTimezone').val()).format());
|
||||||
|
});
|
||||||
|
|
||||||
|
// 生成规则按钮
|
||||||
|
$('#generateRuleBtn').click(generateRule);
|
||||||
|
|
||||||
|
// 生成规则
|
||||||
|
function generateRule() {
|
||||||
|
const serverIds = $('#serverIds').val().split(',').map(id => id.trim());
|
||||||
|
const cycleStart = $('#cycleStart').val();
|
||||||
|
const trafficType = $('#trafficType').val();
|
||||||
|
const cycleUnit = $('#cycleUnit').val();
|
||||||
|
const cycleInterval = parseInt($('#cycleInterval').val());
|
||||||
|
const maxTraffic = $('#maxTraffic').val() * $('#trafficUnit').val();
|
||||||
|
|
||||||
|
if (!validateInput(serverIds, cycleStart, trafficType, cycleUnit, cycleInterval, maxTraffic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rule = [{
|
||||||
|
type: trafficType,
|
||||||
|
max: maxTraffic,
|
||||||
|
cycle_start: cycleStart,
|
||||||
|
cycle_interval: cycleInterval,
|
||||||
|
cycle_unit: cycleUnit,
|
||||||
|
cover: 1,
|
||||||
|
ignore: serverIds.reduce((obj, id) => {
|
||||||
|
obj[id] = true;
|
||||||
|
return obj;
|
||||||
|
}, {})
|
||||||
|
}];
|
||||||
|
|
||||||
|
const ruleJson = JSON.stringify(rule, null, 2);
|
||||||
|
$('#ruleOutput').text(ruleJson);
|
||||||
|
hljs.highlightBlock(document.getElementById('ruleOutput'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复制规则按钮
|
||||||
|
$('#copyRuleBtn').click(function () {
|
||||||
|
const ruleOutput = document.getElementById('ruleOutput');
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNode(ruleOutput);
|
||||||
|
window.getSelection().removeAllRanges();
|
||||||
|
window.getSelection().addRange(range);
|
||||||
|
document.execCommand('copy');
|
||||||
|
window.getSelection().removeAllRanges();
|
||||||
|
showSuccessModal('JSON 规则已复制到剪贴板');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 输入验证
|
||||||
|
function validateInput(serverIds, cycleStart, trafficType, cycleUnit, cycleInterval, maxTraffic) {
|
||||||
|
if (serverIds.length === 0 || (serverIds.length === 1 && serverIds[0] === '')) {
|
||||||
|
showErrorModal('请输入服务器 ID');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cycleStart) {
|
||||||
|
showErrorModal('请选择统计周期开始时间');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!trafficType) {
|
||||||
|
showErrorModal('请选择流量类型');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cycleUnit) {
|
||||||
|
showErrorModal('请选择周期单位');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(cycleInterval) || cycleInterval <= 0) {
|
||||||
|
showErrorModal('请输入有效的周期间隔 (大于 0 的数字)');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(maxTraffic) || maxTraffic <= 0) {
|
||||||
|
showErrorModal('请输入有效的流量上限 (大于 0 的数字)');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时区选择器变更事件
|
||||||
|
$('#cycleStartTimezone').change(updateCycleStart);
|
||||||
|
|
||||||
|
|
||||||
|
function showErrorModal(message) {
|
||||||
|
$('#errorMessage').text(message);
|
||||||
|
$('#errorModal').modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function showSuccessModal(message) {
|
||||||
|
$('#errorMessage').text(message);
|
||||||
|
$('#errorModal').modal('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
21
styles.css
Normal file
21
styles.css
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
body {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ruleOutput {
|
||||||
|
font-family: 'Courier New', Courier, monospace;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rule-output {
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user