Files
NetVizor/src/NetVizor.Frontend/html/design/firewall/firewall-dashboard.html
T
2025-07-28 16:46:18 +08:00

1148 lines
40 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防火墙管理控制台</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--bg-primary: #0a0e27;
--bg-secondary: #151932;
--bg-card: #1a1f3a;
--bg-hover: #242a4a;
--text-primary: #ffffff;
--text-secondary: #a8b2d1;
--text-muted: #64748b;
--accent: #3b82f6;
--accent-hover: #2563eb;
--success: #10b981;
--danger: #ef4444;
--warning: #f59e0b;
--border: #2d3561;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
min-height: 100vh;
line-height: 1.6;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
.header {
background: var(--bg-secondary);
padding: 24px 32px;
border-radius: 16px;
margin-bottom: 32px;
box-shadow: 0 4px 24px rgba(0,0,0,0.3);
display: flex;
justify-content: space-between;
align-items: center;
backdrop-filter: blur(10px);
border: 1px solid var(--border);
}
.header h1 {
font-size: 28px;
font-weight: 600;
background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 32px;
}
.stat-card {
background: var(--bg-card);
padding: 24px;
border-radius: 12px;
border: 1px solid var(--border);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, var(--accent) 0%, #60a5fa 100%);
transform: translateX(-100%);
transition: transform 0.3s ease;
}
.stat-card:hover::before {
transform: translateX(0);
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 32px rgba(59, 130, 246, 0.2);
}
.stat-value {
font-size: 36px;
font-weight: 700;
margin-bottom: 8px;
}
.stat-label {
color: var(--text-secondary);
font-size: 14px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
flex-wrap: wrap;
gap: 16px;
}
.search-box {
flex: 1;
max-width: 400px;
position: relative;
}
.search-box input {
width: 100%;
padding: 12px 48px 12px 20px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-primary);
font-size: 14px;
transition: all 0.3s ease;
}
.search-box input:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.search-icon {
position: absolute;
right: 16px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
}
.filter-buttons {
display: flex;
gap: 12px;
}
.filter-btn {
padding: 8px 16px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-secondary);
cursor: pointer;
transition: all 0.3s ease;
font-size: 14px;
}
.filter-btn:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
.filter-btn.active {
background: var(--accent);
color: white;
border-color: var(--accent);
}
.btn-primary {
padding: 12px 24px;
background: linear-gradient(135deg, var(--accent) 0%, #2563eb 100%);
border: none;
border-radius: 8px;
color: white;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
box-shadow: 0 4px 16px rgba(59, 130, 246, 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 24px rgba(59, 130, 246, 0.4);
}
.rules-table {
background: var(--bg-card);
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--border);
box-shadow: 0 4px 24px rgba(0,0,0,0.2);
}
.table-header {
display: grid;
grid-template-columns: 40px 2fr 1fr 1fr 100px 100px 120px 100px 100px 60px;
padding: 16px 24px;
background: var(--bg-secondary);
border-bottom: 1px solid var(--border);
font-weight: 600;
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--text-secondary);
}
.rule-row {
display: grid;
grid-template-columns: 40px 2fr 1fr 1fr 100px 100px 120px 100px 100px 60px;
padding: 16px 24px;
border-bottom: 1px solid var(--border);
transition: all 0.3s ease;
cursor: pointer;
align-items: center;
}
.rule-row:hover {
background: var(--bg-hover);
transform: translateX(4px);
}
.rule-row:last-child {
border-bottom: none;
}
.checkbox {
width: 20px;
height: 20px;
accent-color: var(--accent);
}
.rule-name {
font-weight: 500;
color: var(--text-primary);
}
.rule-program {
color: var(--text-secondary);
font-size: 13px;
}
.status-badge {
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
display: inline-block;
}
.status-enabled {
background: rgba(16, 185, 129, 0.2);
color: var(--success);
}
.status-disabled {
background: rgba(239, 68, 68, 0.2);
color: var(--danger);
}
.direction-badge {
padding: 4px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
}
.direction-in {
background: rgba(59, 130, 246, 0.2);
color: #60a5fa;
}
.direction-out {
background: rgba(245, 158, 11, 0.2);
color: var(--warning);
}
.actions {
display: flex;
gap: 8px;
}
.action-btn {
width: 32px;
height: 32px;
border: none;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
border-radius: 6px;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.action-btn:hover {
background: var(--bg-hover);
color: var(--accent);
}
/* 模态框样式 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(4px);
z-index: 1000;
animation: fadeIn 0.3s ease;
}
.modal.active {
display: flex;
align-items: center;
justify-content: center;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.modal-content {
background: var(--bg-card);
width: 90%;
max-width: 800px;
max-height: 90vh;
overflow-y: auto;
border-radius: 16px;
border: 1px solid var(--border);
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from {
transform: translateY(20px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.modal-header {
padding: 24px 32px;
border-bottom: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: center;
background: var(--bg-secondary);
}
.modal-header h2 {
font-size: 20px;
font-weight: 600;
}
.close-btn {
width: 40px;
height: 40px;
border: none;
background: transparent;
color: var(--text-secondary);
cursor: pointer;
border-radius: 8px;
font-size: 24px;
transition: all 0.3s ease;
}
.close-btn:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
.modal-body {
padding: 32px;
}
.form-section {
margin-bottom: 32px;
}
.form-section:last-child {
margin-bottom: 0;
}
.section-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 16px;
color: var(--text-primary);
display: flex;
align-items: center;
gap: 8px;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
margin-bottom: 8px;
font-size: 14px;
color: var(--text-secondary);
}
.form-input, .form-select, .form-textarea {
width: 100%;
padding: 12px 16px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-primary);
font-size: 14px;
transition: all 0.3s ease;
}
.form-input:focus, .form-select:focus, .form-textarea:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}
.form-textarea {
resize: vertical;
min-height: 100px;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.radio-group, .checkbox-group {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.radio-label, .checkbox-label {
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
font-size: 14px;
}
.service-list {
max-height: 200px;
overflow-y: auto;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
padding: 12px;
}
.service-item {
padding: 8px;
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
border-radius: 4px;
transition: all 0.3s ease;
}
.service-item:hover {
background: var(--bg-hover);
}
.modal-footer {
padding: 24px 32px;
border-top: 1px solid var(--border);
display: flex;
justify-content: flex-end;
gap: 12px;
background: var(--bg-secondary);
}
.btn-secondary {
padding: 12px 24px;
background: transparent;
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-secondary);
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-secondary:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
/* 滚动条样式 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-secondary);
}
::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--accent);
}
/* 响应式设计 */
@media (max-width: 1200px) {
.table-header, .rule-row {
grid-template-columns: 40px 2fr 1fr 80px 80px 100px 60px;
}
.rule-protocol, .rule-scope {
display: none;
}
}
@media (max-width: 768px) {
.stats {
grid-template-columns: 1fr;
}
.controls {
flex-direction: column;
}
.search-box {
max-width: 100%;
}
.form-row {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<!-- 页头 -->
<div class="header">
<h1>🛡️ 防火墙管理控制台</h1>
<div class="header-actions">
<button class="btn-primary" onclick="openModal()">
<span>+</span>
<span>新建规则</span>
</button>
</div>
</div>
<!-- 统计卡片 -->
<div class="stats">
<div class="stat-card">
<div class="stat-value" id="totalRules">42</div>
<div class="stat-label">总规则数</div>
</div>
<div class="stat-card">
<div class="stat-value" id="activeRules">38</div>
<div class="stat-label">活动规则</div>
</div>
<div class="stat-card">
<div class="stat-value" id="inboundRules">18</div>
<div class="stat-label">入站规则</div>
</div>
<div class="stat-card">
<div class="stat-value" id="outboundRules">24</div>
<div class="stat-label">出站规则</div>
</div>
</div>
<!-- 控制栏 -->
<div class="controls">
<div class="search-box">
<input type="text" placeholder="搜索规则名称、程序或端口..." id="searchInput">
<span class="search-icon">🔍</span>
</div>
<div class="filter-buttons">
<button class="filter-btn active" onclick="filterRules('all')">全部</button>
<button class="filter-btn" onclick="filterRules('inbound')">入站</button>
<button class="filter-btn" onclick="filterRules('outbound')">出站</button>
<button class="filter-btn" onclick="filterRules('enabled')">已启用</button>
<button class="filter-btn" onclick="filterRules('disabled')">已禁用</button>
</div>
</div>
<!-- 规则表格 -->
<div class="rules-table">
<div class="table-header">
<div></div>
<div>名称</div>
<div>程序</div>
<div>协议</div>
<div>端口</div>
<div>远程端口</div>
<div>作用域</div>
<div>方向</div>
<div>状态</div>
<div>操作</div>
</div>
<div id="rulesContainer">
<!-- 规则将通过JavaScript动态生成 -->
</div>
</div>
</div>
<!-- 新建/编辑规则模态框 -->
<div class="modal" id="ruleModal">
<div class="modal-content">
<div class="modal-header">
<h2 id="modalTitle">新建防火墙规则</h2>
<button class="close-btn" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body">
<!-- 基本信息 -->
<div class="form-section">
<h3 class="section-title">📋 基本信息</h3>
<div class="form-group">
<label class="form-label">规则名称</label>
<input type="text" class="form-input" id="ruleName" placeholder="输入规则名称">
</div>
<div class="form-group">
<label class="form-label">描述</label>
<textarea class="form-textarea" id="ruleDescription" placeholder="输入规则描述(可选)"></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">规则类型</label>
<select class="form-select" id="ruleType">
<option value="program">程序</option>
<option value="port">端口</option>
<option value="predefined">预定义</option>
<option value="custom">自定义</option>
</select>
</div>
<div class="form-group">
<label class="form-label">方向</label>
<div class="radio-group">
<label class="radio-label">
<input type="radio" name="direction" value="inbound" checked>
入站
</label>
<label class="radio-label">
<input type="radio" name="direction" value="outbound">
出站
</label>
</div>
</div>
</div>
</div>
<!-- 程序设置 -->
<div class="form-section">
<h3 class="section-title">💻 程序设置</h3>
<div class="form-group">
<label class="form-label">程序路径</label>
<input type="text" class="form-input" id="programPath" placeholder="例如:C:\Program Files\MyApp\app.exe">
</div>
<div class="form-group">
<label class="form-label">应用于服务</label>
<div class="checkbox-group">
<label class="checkbox-label">
<input type="checkbox" id="applyToAllServices">
应用于所有程序和服务
</label>
<label class="checkbox-label">
<input type="checkbox" id="applyToServices">
仅应用于服务
</label>
</div>
</div>
<div class="form-group">
<label class="form-label">选择服务</label>
<div class="service-list">
<div class="service-item">
<input type="checkbox" id="service1">
<label for="service1">Windows Update</label>
</div>
<div class="service-item">
<input type="checkbox" id="service2">
<label for="service2">Windows Defender</label>
</div>
<div class="service-item">
<input type="checkbox" id="service3">
<label for="service3">Remote Desktop</label>
</div>
<div class="service-item">
<input type="checkbox" id="service4">
<label for="service4">SQL Server</label>
</div>
<div class="service-item">
<input type="checkbox" id="service5">
<label for="service5">IIS</label>
</div>
</div>
</div>
</div>
<!-- 协议和端口 -->
<div class="form-section">
<h3 class="section-title">🔌 协议和端口</h3>
<div class="form-row">
<div class="form-group">
<label class="form-label">协议类型</label>
<select class="form-select" id="protocolType">
<option value="any">任意</option>
<option value="tcp">TCP</option>
<option value="udp">UDP</option>
<option value="icmpv4">ICMPv4</option>
<option value="icmpv6">ICMPv6</option>
<option value="custom">自定义</option>
</select>
</div>
<div class="form-group">
<label class="form-label">协议编号</label>
<input type="number" class="form-input" id="protocolNumber" placeholder="0-255" disabled>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">本地端口</label>
<input type="text" class="form-input" id="localPort" placeholder="例如:80, 443, 1000-2000">
</div>
<div class="form-group">
<label class="form-label">远程端口</label>
<input type="text" class="form-input" id="remotePort" placeholder="例如:80, 443, 1000-2000">
</div>
</div>
</div>
<!-- 作用域 -->
<div class="form-section">
<h3 class="section-title">🌐 作用域</h3>
<div class="form-group">
<label class="form-label">本地IP地址</label>
<div class="radio-group">
<label class="radio-label">
<input type="radio" name="localIP" value="any" checked>
任何IP地址
</label>
<label class="radio-label">
<input type="radio" name="localIP" value="specific">
指定IP地址
</label>
</div>
<input type="text" class="form-input" id="localIPList" placeholder="例如:192.168.1.0/24" style="margin-top: 10px; display: none;">
</div>
<div class="form-group">
<label class="form-label">远程IP地址</label>
<div class="radio-group">
<label class="radio-label">
<input type="radio" name="remoteIP" value="any" checked>
任何IP地址
</label>
<label class="radio-label">
<input type="radio" name="remoteIP" value="specific">
指定IP地址
</label>
</div>
<input type="text" class="form-input" id="remoteIPList" placeholder="例如:10.0.0.0/8" style="margin-top: 10px; display: none;">
</div>
</div>
<!-- 高级设置 -->
<div class="form-section">
<h3 class="section-title">⚙️ 高级设置</h3>
<div class="form-group">
<label class="form-label">配置文件</label>
<div class="checkbox-group">
<label class="checkbox-label">
<input type="checkbox" id="profileDomain" checked>
域
</label>
<label class="checkbox-label">
<input type="checkbox" id="profilePrivate" checked>
专用
</label>
<label class="checkbox-label">
<input type="checkbox" id="profilePublic" checked>
公用
</label>
</div>
</div>
<div class="form-group">
<label class="form-label">用户和计算机</label>
<div class="radio-group">
<label class="radio-label">
<input type="radio" name="users" value="all" checked>
所有用户和计算机
</label>
<label class="radio-label">
<input type="radio" name="users" value="specific">
指定用户或组
</label>
</div>
<input type="text" class="form-input" id="userList" placeholder="输入用户或组名称" style="margin-top: 10px; display: none;">
</div>
<div class="form-group">
<label class="form-label">操作</label>
<div class="radio-group">
<label class="radio-label">
<input type="radio" name="action" value="allow" checked>
允许连接
</label>
<label class="radio-label">
<input type="radio" name="action" value="block">
阻止连接
</label>
<label class="radio-label">
<input type="radio" name="action" value="secure">
允许安全连接
</label>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn-secondary" onclick="closeModal()">取消</button>
<button class="btn-primary" onclick="saveRule()">保存规则</button>
</div>
</div>
</div>
<script>
// 模拟防火墙规则数据
let rules = [
{
id: 1,
name: "Chrome 浏览器",
program: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
protocol: "TCP",
port: "80, 443",
remotePort: "任意",
scope: "任意",
direction: "outbound",
status: "enabled",
action: "允许"
},
{
id: 2,
name: "远程桌面 - 用户模式 (TCP-In)",
program: "系统",
protocol: "TCP",
port: "3389",
remotePort: "任意",
scope: "任意",
direction: "inbound",
status: "enabled",
action: "允许"
},
{
id: 3,
name: "Windows Media Player",
program: "C:\\Program Files\\Windows Media Player\\wmplayer.exe",
protocol: "UDP",
port: "554, 8554",
remotePort: "任意",
scope: "本地子网",
direction: "inbound",
status: "disabled",
action: "允许"
},
{
id: 4,
name: "SQL Server",
program: "C:\\Program Files\\Microsoft SQL Server\\MSSQL\\Binn\\sqlservr.exe",
protocol: "TCP",
port: "1433",
remotePort: "任意",
scope: "192.168.1.0/24",
direction: "inbound",
status: "enabled",
action: "允许"
},
{
id: 5,
name: "核心网络 - DHCP (Out)",
program: "系统",
protocol: "UDP",
port: "68",
remotePort: "67",
scope: "任意",
direction: "outbound",
status: "enabled",
action: "允许"
}
];
let currentFilter = 'all';
let editingRule = null;
// 渲染规则列表
function renderRules() {
const container = document.getElementById('rulesContainer');
container.innerHTML = '';
let filteredRules = rules;
// 应用过滤器
if (currentFilter === 'inbound') {
filteredRules = rules.filter(r => r.direction === 'inbound');
} else if (currentFilter === 'outbound') {
filteredRules = rules.filter(r => r.direction === 'outbound');
} else if (currentFilter === 'enabled') {
filteredRules = rules.filter(r => r.status === 'enabled');
} else if (currentFilter === 'disabled') {
filteredRules = rules.filter(r => r.status === 'disabled');
}
// 应用搜索
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
if (searchTerm) {
filteredRules = filteredRules.filter(r =>
r.name.toLowerCase().includes(searchTerm) ||
r.program.toLowerCase().includes(searchTerm) ||
r.port.toLowerCase().includes(searchTerm)
);
}
filteredRules.forEach(rule => {
const row = document.createElement('div');
row.className = 'rule-row';
row.innerHTML = `
<div><input type="checkbox" class="checkbox"></div>
<div class="rule-name">${rule.name}</div>
<div class="rule-program">${rule.program}</div>
<div>${rule.protocol}</div>
<div>${rule.port}</div>
<div>${rule.remotePort}</div>
<div class="rule-scope">${rule.scope}</div>
<div><span class="direction-badge direction-${rule.direction === 'inbound' ? 'in' : 'out'}">${rule.direction === 'inbound' ? '入站' : '出站'}</span></div>
<div><span class="status-badge status-${rule.status}">${rule.status === 'enabled' ? '已启用' : '已禁用'}</span></div>
<div class="actions">
<button class="action-btn" onclick="editRule(${rule.id})" title="编辑">✏️</button>
<button class="action-btn" onclick="deleteRule(${rule.id})" title="删除">🗑️</button>
</div>
`;
row.onclick = (e) => {
if (!e.target.classList.contains('action-btn') && e.target.type !== 'checkbox') {
editRule(rule.id);
}
};
container.appendChild(row);
});
updateStats();
}
// 更新统计信息
function updateStats() {
document.getElementById('totalRules').textContent = rules.length;
document.getElementById('activeRules').textContent = rules.filter(r => r.status === 'enabled').length;
document.getElementById('inboundRules').textContent = rules.filter(r => r.direction === 'inbound').length;
document.getElementById('outboundRules').textContent = rules.filter(r => r.direction === 'outbound').length;
}
// 过滤规则
function filterRules(filter) {
currentFilter = filter;
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.classList.remove('active');
});
event.target.classList.add('active');
renderRules();
}
// 打开模态框
function openModal() {
document.getElementById('ruleModal').classList.add('active');
document.getElementById('modalTitle').textContent = '新建防火墙规则';
editingRule = null;
clearForm();
}
// 关闭模态框
function closeModal() {
document.getElementById('ruleModal').classList.remove('active');
editingRule = null;
}
// 编辑规则
function editRule(id) {
const rule = rules.find(r => r.id === id);
if (rule) {
editingRule = rule;
document.getElementById('modalTitle').textContent = '编辑防火墙规则';
document.getElementById('ruleName').value = rule.name;
document.getElementById('programPath').value = rule.program;
document.getElementById('protocolType').value = rule.protocol.toLowerCase();
document.getElementById('localPort').value = rule.port;
document.getElementById('remotePort').value = rule.remotePort === '任意' ? '' : rule.remotePort;
document.querySelector(`input[name="direction"][value="${rule.direction}"]`).checked = true;
document.querySelector(`input[name="action"][value="allow"]`).checked = rule.action === '允许';
document.getElementById('ruleModal').classList.add('active');
}
}
// 删除规则
function deleteRule(id) {
if (confirm('确定要删除这条规则吗?')) {
rules = rules.filter(r => r.id !== id);
renderRules();
}
}
// 保存规则
function saveRule() {
const name = document.getElementById('ruleName').value;
const program = document.getElementById('programPath').value || '系统';
const protocol = document.getElementById('protocolType').value.toUpperCase();
const port = document.getElementById('localPort').value || '任意';
const remotePort = document.getElementById('remotePort').value || '任意';
const direction = document.querySelector('input[name="direction"]:checked').value;
const action = document.querySelector('input[name="action"]:checked').value === 'allow' ? '允许' : '阻止';
if (!name) {
alert('请输入规则名称');
return;
}
if (editingRule) {
// 更新现有规则
editingRule.name = name;
editingRule.program = program;
editingRule.protocol = protocol;
editingRule.port = port;
editingRule.remotePort = remotePort;
editingRule.direction = direction;
editingRule.action = action;
} else {
// 创建新规则
const newRule = {
id: Date.now(),
name,
program,
protocol,
port,
remotePort,
scope: '任意',
direction,
status: 'enabled',
action
};
rules.push(newRule);
}
renderRules();
closeModal();
}
// 清空表单
function clearForm() {
document.getElementById('ruleName').value = '';
document.getElementById('ruleDescription').value = '';
document.getElementById('programPath').value = '';
document.getElementById('protocolType').value = 'any';
document.getElementById('localPort').value = '';
document.getElementById('remotePort').value = '';
document.querySelector('input[name="direction"][value="inbound"]').checked = true;
document.querySelector('input[name="action"][value="allow"]').checked = true;
}
// 搜索功能
document.getElementById('searchInput').addEventListener('input', renderRules);
// 协议类型变化时的处理
document.getElementById('protocolType').addEventListener('change', function() {
const protocolNumber = document.getElementById('protocolNumber');
if (this.value === 'custom') {
protocolNumber.disabled = false;
} else {
protocolNumber.disabled = true;
protocolNumber.value = '';
}
});
// IP地址选择的处理
document.querySelectorAll('input[name="localIP"]').forEach(radio => {
radio.addEventListener('change', function() {
const localIPList = document.getElementById('localIPList');
if (this.value === 'specific') {
localIPList.style.display = 'block';
} else {
localIPList.style.display = 'none';
}
});
});
document.querySelectorAll('input[name="remoteIP"]').forEach(radio => {
radio.addEventListener('change', function() {
const remoteIPList = document.getElementById('remoteIPList');
if (this.value === 'specific') {
remoteIPList.style.display = 'block';
} else {
remoteIPList.style.display = 'none';
}
});
});
// 用户选择的处理
document.querySelectorAll('input[name="users"]').forEach(radio => {
radio.addEventListener('change', function() {
const userList = document.getElementById('userList');
if (this.value === 'specific') {
userList.style.display = 'block';
} else {
userList.style.display = 'none';
}
});
});
// 点击模态框外部关闭
document.getElementById('ruleModal').addEventListener('click', function(e) {
if (e.target === this) {
closeModal();
}
});
// 初始化
renderRules();
</script>
</body>
</html>