This commit is contained in:
jimmy committed 2025-07-28 16:46:07 +08:00
1 parent 1491757e7f
commit 74962ebd8b
2 files changed
-2316

No files matched your search

@@ -1,1083 +0,0 @@
<!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: #0a0f1c;
--bg-secondary: #131a2a;
--bg-card: rgba(20, 27, 45, 0.8);
--text-primary: #e4e8f1;
--text-secondary: #8b92a8;
--accent: #3b82f6;
--accent-hover: #2563eb;
--success: #10b981;
--danger: #ef4444;
--warning: #f59e0b;
--border: rgba(255, 255, 255, 0.1);
--glass: rgba(255, 255, 255, 0.05);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
overflow-x: hidden;
}
/* 背景动画 */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle at 20% 50%, rgba(59, 130, 246, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 80%, rgba(16, 185, 129, 0.1) 0%, transparent 50%);
z-index: -1;
}
/* 主容器 */
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
/* 头部 */
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding: 20px 0;
border-bottom: 1px solid var(--border);
}
.header h1 {
font-size: 2.5rem;
font-weight: 700;
background: linear-gradient(135deg, var(--accent) 0%, var(--success) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* 统计卡片 */
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: var(--bg-card);
backdrop-filter: blur(10px);
border: 1px solid var(--border);
border-radius: 16px;
padding: 24px;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(90deg, var(--accent) 0%, var(--success) 100%);
}
.stat-card:hover {
transform: translateY(-4px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}
.stat-value {
font-size: 2.5rem;
font-weight: 700;
margin: 10px 0;
}
.stat-label {
color: var(--text-secondary);
font-size: 0.9rem;
}
/* 过滤和操作栏 */
.action-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
flex-wrap: wrap;
gap: 15px;
}
.filter-group {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
font-size: 0.9rem;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 8px;
font-weight: 500;
}
.btn-primary {
background: var(--accent);
color: white;
}
.btn-primary:hover {
background: var(--accent-hover);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(59, 130, 246, 0.3);
}
.btn-secondary {
background: var(--glass);
color: var(--text-primary);
border: 1px solid var(--border);
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.1);
}
.btn-danger {
background: var(--danger);
color: white;
}
.search-box {
position: relative;
width: 300px;
}
.search-box input {
width: 100%;
padding: 10px 40px 10px 15px;
background: var(--glass);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-primary);
font-size: 0.9rem;
transition: all 0.3s ease;
}
.search-box input:focus {
outline: none;
border-color: var(--accent);
background: rgba(255, 255, 255, 0.1);
}
/* 规则表格 */
.rules-table {
background: var(--bg-card);
backdrop-filter: blur(10px);
border: 1px solid var(--border);
border-radius: 16px;
overflow: hidden;
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background: var(--bg-secondary);
padding: 15px;
text-align: left;
font-weight: 600;
font-size: 0.9rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
td {
padding: 15px;
border-top: 1px solid var(--border);
}
tr {
transition: all 0.3s ease;
cursor: pointer;
}
tr:hover {
background: rgba(255, 255, 255, 0.03);
}
.status-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.85rem;
font-weight: 500;
}
.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 {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
border-radius: 6px;
font-size: 0.85rem;
background: var(--glass);
border: 1px solid var(--border);
}
/* 模态框 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(5px);
z-index: 1000;
animation: fadeIn 0.3s ease;
}
.modal.active {
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background: var(--bg-secondary);
border-radius: 20px;
width: 90%;
max-width: 800px;
max-height: 90vh;
overflow-y: auto;
animation: slideUp 0.3s ease;
border: 1px solid var(--border);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.modal-header {
padding: 30px;
border-bottom: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-header h2 {
font-size: 1.8rem;
font-weight: 600;
}
.close-btn {
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--glass);
border: 1px solid var(--border);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.close-btn:hover {
background: rgba(255, 255, 255, 0.1);
transform: rotate(90deg);
}
.modal-body {
padding: 30px;
}
.form-group {
margin-bottom: 25px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: var(--text-secondary);
font-size: 0.9rem;
}
.form-control {
width: 100%;
padding: 12px 15px;
background: var(--glass);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-primary);
font-size: 0.95rem;
transition: all 0.3s ease;
}
.form-control:focus {
outline: none;
border-color: var(--accent);
background: rgba(255, 255, 255, 0.08);
}
select.form-control {
cursor: pointer;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.tabs {
display: flex;
gap: 10px;
margin-bottom: 30px;
border-bottom: 1px solid var(--border);
}
.tab {
padding: 12px 24px;
background: none;
border: none;
color: var(--text-secondary);
cursor: pointer;
font-weight: 500;
position: relative;
transition: all 0.3s ease;
}
.tab.active {
color: var(--text-primary);
}
.tab.active::after {
content: '';
position: absolute;
bottom: -1px;
left: 0;
width: 100%;
height: 2px;
background: var(--accent);
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.checkbox-group {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.checkbox-item {
display: flex;
align-items: center;
gap: 8px;
}
.checkbox-item input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
.modal-footer {
padding: 20px 30px;
border-top: 1px solid var(--border);
display: flex;
justify-content: flex-end;
gap: 10px;
}
/* 动画 */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from { transform: translateY(50px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
/* 服务选择器 */
.service-selector {
max-height: 200px;
overflow-y: auto;
border: 1px solid var(--border);
border-radius: 8px;
padding: 10px;
background: var(--glass);
}
.service-item {
padding: 8px;
margin: 2px 0;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
}
.service-item:hover {
background: rgba(255, 255, 255, 0.05);
}
.service-item input {
margin-right: 8px;
}
/* 响应式 */
@media (max-width: 768px) {
.header h1 {
font-size: 1.8rem;
}
.action-bar {
flex-direction: column;
align-items: stretch;
}
.search-box {
width: 100%;
}
.form-row {
grid-template-columns: 1fr;
}
.modal-content {
width: 95%;
max-height: 95vh;
}
}
</style>
</head>
<body>
<div class="container">
<!-- 头部 -->
<div class="header">
<h1>防火墙管理中心</h1>
<div class="header-actions">
<button class="btn btn-secondary" onclick="exportRules()">
<span>📤</span> 导出规则
</button>
<button class="btn btn-secondary" onclick="importRules()">
<span>📥</span> 导入规则
</button>
</div>
</div>
<!-- 统计卡片 -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-label">总规则数</div>
<div class="stat-value" id="total-rules">42</div>
<div class="stat-label">入站: 24 | 出站: 18</div>
</div>
<div class="stat-card">
<div class="stat-label">已启用规则</div>
<div class="stat-value" style="color: var(--success);">35</div>
<div class="stat-label">占比 83.3%</div>
</div>
<div class="stat-card">
<div class="stat-label">已禁用规则</div>
<div class="stat-value" style="color: var(--danger);">7</div>
<div class="stat-label">占比 16.7%</div>
</div>
<div class="stat-card">
<div class="stat-label">安全等级</div>
<div class="stat-value" style="color: var(--success);">高</div>
<div class="stat-label">系统防护良好</div>
</div>
</div>
<!-- 过滤和操作栏 -->
<div class="action-bar">
<div class="filter-group">
<button class="btn btn-secondary" onclick="filterRules('all')">全部</button>
<button class="btn btn-secondary" onclick="filterRules('inbound')">入站</button>
<button class="btn btn-secondary" onclick="filterRules('outbound')">出站</button>
<button class="btn btn-secondary" onclick="filterRules('enabled')">已启用</button>
<button class="btn btn-secondary" onclick="filterRules('disabled')">已禁用</button>
</div>
<div class="search-box">
<input type="text" placeholder="搜索规则名称、程序、端口..." onkeyup="searchRules(this.value)">
</div>
<button class="btn btn-primary" onclick="openAddModal()">
<span>➕</span> 新建规则
</button>
</div>
<!-- 规则表格 -->
<div class="rules-table">
<table>
<thead>
<tr>
<th>状态</th>
<th>名称</th>
<th>方向</th>
<th>程序</th>
<th>协议</th>
<th>端口</th>
<th>远程地址</th>
<th>操作</th>
</tr>
</thead>
<tbody id="rules-tbody">
<!-- 动态生成的规则行 -->
</tbody>
</table>
</div>
</div>
<!-- 添加/编辑规则模态框 -->
<div class="modal" id="rule-modal">
<div class="modal-content">
<div class="modal-header">
<h2 id="modal-title">新建防火墙规则</h2>
<button class="close-btn" onclick="closeModal()">✕</button>
</div>
<div class="modal-body">
<!-- 标签页 -->
<div class="tabs">
<button class="tab active" onclick="switchTab('general')">常规</button>
<button class="tab" onclick="switchTab('program')">程序和服务</button>
<button class="tab" onclick="switchTab('protocol')">协议和端口</button>
<button class="tab" onclick="switchTab('scope')">作用域</button>
<button class="tab" onclick="switchTab('advanced')">高级</button>
</div>
<!-- 常规标签页 -->
<div class="tab-content active" id="general-tab">
<div class="form-group">
<label>规则名称 *</label>
<input type="text" class="form-control" id="rule-name" placeholder="输入规则名称">
</div>
<div class="form-group">
<label>描述</label>
<textarea class="form-control" id="rule-description" rows="3" placeholder="输入规则描述"></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label>方向 *</label>
<select class="form-control" id="rule-direction">
<option value="inbound">入站</option>
<option value="outbound">出站</option>
</select>
</div>
<div class="form-group">
<label>操作 *</label>
<select class="form-control" id="rule-action">
<option value="allow">允许连接</option>
<option value="block">阻止连接</option>
<option value="allow-secure">允许安全连接</option>
</select>
</div>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="rule-enabled" checked>
启用此规则
</label>
</div>
</div>
<!-- 程序和服务标签页 -->
<div class="tab-content" id="program-tab">
<div class="form-group">
<label>程序路径</label>
<input type="text" class="form-control" id="program-path" placeholder="例如: C:\Program Files\App\app.exe">
</div>
<div class="form-group">
<label>应用于以下服务</label>
<div class="service-selector">
<div class="service-item">
<label><input type="checkbox" value="BITS"> 后台智能传输服务 (BITS)</label>
</div>
<div class="service-item">
<label><input type="checkbox" value="Dnscache"> DNS 客户端 (Dnscache)</label>
</div>
<div class="service-item">
<label><input type="checkbox" value="Dhcp"> DHCP 客户端 (Dhcp)</label>
</div>
<div class="service-item">
<label><input type="checkbox" value="EventLog"> Windows 事件日志 (EventLog)</label>
</div>
<div class="service-item">
<label><input type="checkbox" value="MpsSvc"> Windows 防火墙 (MpsSvc)</label>
</div>
<div class="service-item">
<label><input type="checkbox" value="RpcSs"> 远程过程调用 (RPC)</label>
</div>
<div class="service-item">
<label><input type="checkbox" value="Spooler"> 打印后台处理程序</label>
</div>
<div class="service-item">
<label><input type="checkbox" value="W32Time"> Windows 时间</label>
</div>
<div class="service-item">
<label><input type="checkbox" value="WinRM"> Windows 远程管理</label>
</div>
</div>
</div>
</div>
<!-- 协议和端口标签页 -->
<div class="tab-content" id="protocol-tab">
<div class="form-group">
<label>协议类型</label>
<select class="form-control" id="protocol-type" onchange="togglePortFields()">
<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" id="custom-protocol-group" style="display: none;">
<label>协议号</label>
<input type="number" class="form-control" id="protocol-number" min="0" max="255" placeholder="0-255">
</div>
<div class="form-row" id="port-fields">
<div class="form-group">
<label>本地端口</label>
<input type="text" class="form-control" id="local-ports" placeholder="例如: 80, 443, 1000-2000">
</div>
<div class="form-group">
<label>远程端口</label>
<input type="text" class="form-control" id="remote-ports" placeholder="例如: 80, 443, 1000-2000">
</div>
</div>
</div>
<!-- 作用域标签页 -->
<div class="tab-content" id="scope-tab">
<div class="form-group">
<label>本地 IP 地址</label>
<div class="checkbox-group">
<div class="checkbox-item">
<input type="radio" name="local-ip" value="any" checked>
<label>任何 IP 地址</label>
</div>
<div class="checkbox-item">
<input type="radio" name="local-ip" value="custom">
<label>指定 IP 地址</label>
</div>
</div>
<input type="text" class="form-control" id="local-ip-list" placeholder="例如: 192.168.1.0/24, 10.0.0.1" style="margin-top: 10px; display: none;">
</div>
<div class="form-group">
<label>远程 IP 地址</label>
<div class="checkbox-group">
<div class="checkbox-item">
<input type="radio" name="remote-ip" value="any" checked>
<label>任何 IP 地址</label>
</div>
<div class="checkbox-item">
<input type="radio" name="remote-ip" value="custom">
<label>指定 IP 地址</label>
</div>
</div>
<input type="text" class="form-control" id="remote-ip-list" placeholder="例如: 192.168.1.0/24, 10.0.0.1" style="margin-top: 10px; display: none;">
</div>
</div>
<!-- 高级标签页 -->
<div class="tab-content" id="advanced-tab">
<div class="form-group">
<label>配置文件</label>
<div class="checkbox-group">
<div class="checkbox-item">
<input type="checkbox" id="profile-domain" checked>
<label>域</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="profile-private" checked>
<label>专用</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="profile-public" checked>
<label>公用</label>
</div>
</div>
</div>
<div class="form-group">
<label>用户和组</label>
<input type="text" class="form-control" id="users-groups" placeholder="例如: DOMAIN\User, Everyone">
</div>
<div class="form-group">
<label>边缘遍历</label>
<select class="form-control" id="edge-traversal">
<option value="block">阻止边缘遍历</option>
<option value="allow">允许边缘遍历</option>
<option value="defer-to-user">延迟到用户</option>
<option value="defer-to-app">延迟到应用程序</option>
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" onclick="closeModal()">取消</button>
<button class="btn btn-primary" onclick="saveRule()">保存规则</button>
</div>
</div>
</div>
<script>
// 模拟规则数据
let rules = [
{
id: 1,
name: "允许 Chrome 浏览器",
enabled: true,
direction: "outbound",
program: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
protocol: "TCP",
localPort: "任意",
remotePort: "80, 443",
remoteAddress: "任意",
action: "allow",
description: "允许 Chrome 浏览器访问网络"
},
{
id: 2,
name: "远程桌面 - 用户模式 (TCP-In)",
enabled: true,
direction: "inbound",
program: "系统",
protocol: "TCP",
localPort: "3389",
remotePort: "任意",
remoteAddress: "任意",
action: "allow",
description: "允许远程桌面连接"
},
{
id: 3,
name: "阻止 SMB 445 端口",
enabled: true,
direction: "inbound",
program: "任意",
protocol: "TCP",
localPort: "445",
remotePort: "任意",
remoteAddress: "任意",
action: "block",
description: "阻止 SMB 文件共享端口"
},
{
id: 4,
name: "Windows 更新服务",
enabled: true,
direction: "outbound",
program: "C:\\Windows\\System32\\svchost.exe",
protocol: "TCP/UDP",
localPort: "任意",
remotePort: "80, 443",
remoteAddress: "任意",
action: "allow",
description: "允许 Windows 更新服务"
},
{
id: 5,
name: "SSH 服务器",
enabled: false,
direction: "inbound",
program: "C:\\Program Files\\OpenSSH\\sshd.exe",
protocol: "TCP",
localPort: "22",
remotePort: "任意",
remoteAddress: "192.168.1.0/24",
action: "allow",
description: "SSH 服务器访问规则"
}
];
let currentEditId = null;
// 渲染规则表格
function renderRules() {
const tbody = document.getElementById('rules-tbody');
tbody.innerHTML = '';
rules.forEach(rule => {
const tr = document.createElement('tr');
tr.onclick = () => editRule(rule.id);
tr.innerHTML = `
<td>
<span class="status-badge ${rule.enabled ? 'status-enabled' : 'status-disabled'}">
<span style="font-size: 0.8rem;">${rule.enabled ? '●' : '○'}</span>
${rule.enabled ? '启用' : '禁用'}
</span>
</td>
<td>${rule.name}</td>
<td>
<span class="direction-badge">
${rule.direction === 'inbound' ? '⬅️ 入站' : '➡️ 出站'}
</span>
</td>
<td>${rule.program.length > 30 ? '...' + rule.program.substr(-30) : rule.program}</td>
<td>${rule.protocol}</td>
<td>${rule.localPort}</td>
<td>${rule.remoteAddress}</td>
<td>
<span style="color: ${rule.action === 'allow' ? 'var(--success)' : 'var(--danger)'}">
${rule.action === 'allow' ? '✓ 允许' : '✗ 阻止'}
</span>
</td>
`;
tbody.appendChild(tr);
});
}
// 打开添加模态框
function openAddModal() {
currentEditId = null;
document.getElementById('modal-title').textContent = '新建防火墙规则';
document.getElementById('rule-modal').classList.add('active');
resetForm();
}
// 编辑规则
function editRule(id) {
currentEditId = id;
const rule = rules.find(r => r.id === id);
if (!rule) return;
document.getElementById('modal-title').textContent = '编辑防火墙规则';
document.getElementById('rule-modal').classList.add('active');
// 填充表单
document.getElementById('rule-name').value = rule.name;
document.getElementById('rule-description').value = rule.description || '';
document.getElementById('rule-direction').value = rule.direction;
document.getElementById('rule-action').value = rule.action;
document.getElementById('rule-enabled').checked = rule.enabled;
document.getElementById('program-path').value = rule.program === '任意' ? '' : rule.program;
// 这里可以继续填充其他字段...
}
// 关闭模态框
function closeModal() {
document.getElementById('rule-modal').classList.remove('active');
}
// 切换标签页
function switchTab(tabName) {
// 更新标签按钮状态
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
});
event.target.classList.add('active');
// 显示对应内容
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
document.getElementById(`${tabName}-tab`).classList.add('active');
}
// 切换端口字段显示
function togglePortFields() {
const protocol = document.getElementById('protocol-type').value;
const portFields = document.getElementById('port-fields');
const customProtocolGroup = document.getElementById('custom-protocol-group');
if (protocol === 'tcp' || protocol === 'udp') {
portFields.style.display = 'grid';
customProtocolGroup.style.display = 'none';
} else if (protocol === 'custom') {
portFields.style.display = 'none';
customProtocolGroup.style.display = 'block';
} else {
portFields.style.display = 'none';
customProtocolGroup.style.display = 'none';
}
}
// 保存规则
function saveRule() {
const name = document.getElementById('rule-name').value.trim();
if (!name) {
alert('请输入规则名称');
return;
}
const rule = {
id: currentEditId || Date.now(),
name: name,
enabled: document.getElementById('rule-enabled').checked,
direction: document.getElementById('rule-direction').value,
program: document.getElementById('program-path').value || '任意',
protocol: document.getElementById('protocol-type').value.toUpperCase(),
localPort: document.getElementById('local-ports').value || '任意',
remotePort: document.getElementById('remote-ports').value || '任意',
remoteAddress: '任意', // 简化处理
action: document.getElementById('rule-action').value,
description: document.getElementById('rule-description').value
};
if (currentEditId) {
// 更新现有规则
const index = rules.findIndex(r => r.id === currentEditId);
if (index !== -1) {
rules[index] = rule;
}
} else {
// 添加新规则
rules.unshift(rule);
}
renderRules();
closeModal();
updateStats();
}
// 重置表单
function resetForm() {
document.getElementById('rule-name').value = '';
document.getElementById('rule-description').value = '';
document.getElementById('rule-direction').value = 'inbound';
document.getElementById('rule-action').value = 'allow';
document.getElementById('rule-enabled').checked = true;
document.getElementById('program-path').value = '';
document.getElementById('protocol-type').value = 'any';
document.getElementById('local-ports').value = '';
document.getElementById('remote-ports').value = '';
// 重置到第一个标签页
document.querySelectorAll('.tab').forEach((tab, index) => {
tab.classList.toggle('active', index === 0);
});
document.querySelectorAll('.tab-content').forEach((content, index) => {
content.classList.toggle('active', index === 0);
});
}
// 过滤规则
function filterRules(type) {
// 实际实现中应该过滤规则
console.log('过滤规则:', type);
}
// 搜索规则
function searchRules(keyword) {
// 实际实现中应该搜索规则
console.log('搜索规则:', keyword);
}
// 更新统计
function updateStats() {
document.getElementById('total-rules').textContent = rules.length;
}
// 导出规则
function exportRules() {
const dataStr = JSON.stringify(rules, null, 2);
const dataBlob = new Blob([dataStr], {type: 'application/json'});
const url = URL.createObjectURL(dataBlob);
const link = document.createElement('a');
link.href = url;
link.download = 'firewall_rules.json';
link.click();
}
// 导入规则
function importRules() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = function(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
try {
const importedRules = JSON.parse(e.target.result);
rules = importedRules;
renderRules();
updateStats();
alert('规则导入成功!');
} catch (err) {
alert('导入失败:文件格式错误');
}
};
reader.readAsText(file);
}
};
input.click();
}
// 处理本地/远程IP选择
document.querySelectorAll('input[name="local-ip"]').forEach(radio => {
radio.addEventListener('change', function() {
document.getElementById('local-ip-list').style.display =
this.value === 'custom' ? 'block' : 'none';
});
});
document.querySelectorAll('input[name="remote-ip"]').forEach(radio => {
radio.addEventListener('change', function() {
document.getElementById('remote-ip-list').style.display =
this.value === 'custom' ? 'block' : 'none';
});
});
// 页面加载时初始化
window.onload = function() {
renderRules();
updateStats();
};
</script>
</body>
</html>
@@ -1,1233 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防火墙管理看板</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.3.4/vue.global.prod.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lucide/0.263.1/lucide.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}
.app-container {
padding: 20px;
max-width: 1400px;
margin: 0 auto;
}
.header {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 16px;
padding: 24px 32px;
margin-bottom: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
color: #2d3748;
font-size: 2rem;
font-weight: 700;
display: flex;
align-items: center;
gap: 12px;
}
.header-stats {
display: flex;
gap: 24px;
}
.stat-item {
text-align: center;
padding: 12px 20px;
background: linear-gradient(135deg, #4f46e5, #7c3aed);
color: white;
border-radius: 12px;
min-width: 80px;
}
.stat-number {
font-size: 1.5rem;
font-weight: 700;
}
.stat-label {
font-size: 0.875rem;
opacity: 0.9;
}
.controls {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 16px;
padding: 20px 32px;
margin-bottom: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.filter-group {
display: flex;
gap: 12px;
align-items: center;
}
.filter-select, .search-input {
padding: 10px 16px;
border: 2px solid #e2e8f0;
border-radius: 8px;
font-size: 14px;
transition: all 0.3s ease;
background: white;
}
.filter-select:focus, .search-input:focus {
outline: none;
border-color: #4f46e5;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}
.search-input {
min-width: 250px;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 8px;
text-decoration: none;
}
.btn-primary {
background: linear-gradient(135deg, #4f46e5, #7c3aed);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(79, 70, 229, 0.3);
}
.btn-success {
background: linear-gradient(135deg, #10b981, #059669);
color: white;
}
.btn-danger {
background: linear-gradient(135deg, #ef4444, #dc2626);
color: white;
}
.btn-secondary {
background: #f1f5f9;
color: #64748b;
border: 1px solid #e2e8f0;
}
.btn:hover {
transform: translateY(-1px);
}
.rules-container {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
overflow: hidden;
}
.rules-header {
padding: 20px 32px;
background: linear-gradient(135deg, #f8fafc, #f1f5f9);
border-bottom: 1px solid #e2e8f0;
}
.rules-grid {
display: grid;
grid-template-columns: 1fr 120px 100px 150px 120px 100px 140px;
gap: 16px;
font-weight: 600;
color: #475569;
}
.rule-item {
display: grid;
grid-template-columns: 1fr 120px 100px 150px 120px 100px 140px;
gap: 16px;
padding: 20px 32px;
border-bottom: 1px solid #f1f5f9;
transition: all 0.3s ease;
align-items: center;
}
.rule-item:hover {
background: rgba(79, 70, 229, 0.05);
transform: translateX(4px);
}
.rule-name {
font-weight: 600;
color: #2d3748;
}
.rule-program {
font-size: 0.875rem;
color: #64748b;
}
.status-badge {
padding: 4px 12px;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
text-align: center;
}
.status-enabled {
background: #dcfce7;
color: #166534;
}
.status-disabled {
background: #fee2e2;
color: #991b1b;
}
.action-badge {
padding: 4px 12px;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
text-align: center;
}
.action-allow {
background: #dcfce7;
color: #166534;
}
.action-block {
background: #fee2e2;
color: #991b1b;
}
.direction-badge {
padding: 4px 12px;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
text-align: center;
}
.direction-inbound {
background: #dbeafe;
color: #1e40af;
}
.direction-outbound {
background: #fef3c7;
color: #92400e;
}
.rule-actions {
display: flex;
gap: 8px;
}
.icon-btn {
width: 32px;
height: 32px;
border: none;
border-radius: 6px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.icon-btn:hover {
transform: scale(1.1);
}
.icon-btn.edit {
background: #f0f9ff;
color: #0369a1;
}
.icon-btn.delete {
background: #fef2f2;
color: #dc2626;
}
.icon-btn.toggle {
background: #f7fee7;
color: #65a30d;
}
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.modal.show {
opacity: 1;
visibility: visible;
}
.modal-content {
background: white;
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
max-width: 800px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
transform: scale(0.9);
transition: transform 0.3s ease;
}
.modal.show .modal-content {
transform: scale(1);
}
.modal-header {
padding: 24px 32px;
border-bottom: 1px solid #e2e8f0;
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-title {
font-size: 1.5rem;
font-weight: 700;
color: #2d3748;
}
.close-btn {
width: 40px;
height: 40px;
border: none;
background: #f1f5f9;
border-radius: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.close-btn:hover {
background: #e2e8f0;
transform: rotate(90deg);
}
.modal-body {
padding: 32px;
}
.form-group {
margin-bottom: 24px;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 24px;
}
.form-label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #374151;
}
.form-input, .form-select, .form-textarea {
width: 100%;
padding: 12px 16px;
border: 2px solid #e2e8f0;
border-radius: 8px;
font-size: 14px;
transition: all 0.3s ease;
}
.form-input:focus, .form-select:focus, .form-textarea:focus {
outline: none;
border-color: #4f46e5;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}
.form-textarea {
resize: vertical;
min-height: 80px;
}
.checkbox-group {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
}
.checkbox {
width: 18px;
height: 18px;
}
.service-list {
max-height: 200px;
overflow-y: auto;
border: 2px solid #e2e8f0;
border-radius: 8px;
padding: 12px;
background: #f8fafc;
}
.service-item {
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
border-radius: 6px;
transition: background 0.2s ease;
}
.service-item:hover {
background: #e2e8f0;
}
.modal-footer {
padding: 24px 32px;
border-top: 1px solid #e2e8f0;
display: flex;
gap: 12px;
justify-content: flex-end;
}
.tabs {
display: flex;
border-bottom: 2px solid #e2e8f0;
margin-bottom: 24px;
}
.tab {
padding: 12px 24px;
cursor: pointer;
border-bottom: 3px solid transparent;
transition: all 0.3s ease;
font-weight: 600;
}
.tab.active {
color: #4f46e5;
border-bottom-color: #4f46e5;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
@media (max-width: 1200px) {
.rules-grid, .rule-item {
grid-template-columns: 1fr 100px 80px 120px 100px 120px;
}
}
@media (max-width: 768px) {
.controls {
flex-direction: column;
align-items: stretch;
}
.filter-group {
justify-content: center;
}
.rules-grid, .rule-item {
grid-template-columns: 1fr;
gap: 8px;
}
.rule-item {
padding: 16px 20px;
}
.modal-content {
width: 95%;
margin: 20px;
}
.form-row {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div id="app" class="app-container">
<!-- Header -->
<div class="header">
<div class="header-content">
<h1>
<i data-lucide="shield"></i>
防火墙管理看板
</h1>
<div class="header-stats">
<div class="stat-item">
<div class="stat-number">{{ enabledRules }}</div>
<div class="stat-label">已启用</div>
</div>
<div class="stat-item">
<div class="stat-number">{{ disabledRules }}</div>
<div class="stat-label">已禁用</div>
</div>
<div class="stat-item">
<div class="stat-number">{{ totalRules }}</div>
<div class="stat-label">总规则</div>
</div>
</div>
</div>
</div>
<!-- Controls -->
<div class="controls">
<div class="filter-group">
<select v-model="filterDirection" class="filter-select">
<option value="">所有方向</option>
<option value="inbound">入站</option>
<option value="outbound">出站</option>
</select>
<select v-model="filterAction" class="filter-select">
<option value="">所有操作</option>
<option value="allow">允许</option>
<option value="block">阻止</option>
</select>
<select v-model="filterStatus" class="filter-select">
<option value="">所有状态</option>
<option value="enabled">已启用</option>
<option value="disabled">已禁用</option>
</select>
</div>
<div class="filter-group">
<input
type="text"
placeholder="搜索规则名称..."
v-model="searchText"
class="search-input"
>
<button class="btn btn-primary" @click="openModal()">
<i data-lucide="plus"></i>
新增规则
</button>
</div>
</div>
<!-- Rules Container -->
<div class="rules-container">
<div class="rules-header">
<div class="rules-grid">
<div>规则名称</div>
<div>方向</div>
<div>操作</div>
<div>协议/端口</div>
<div>状态</div>
<div>作用域</div>
<div>操作</div>
</div>
</div>
<div v-for="rule in filteredRules" :key="rule.id" class="rule-item">
<div>
<div class="rule-name">{{ rule.name }}</div>
<div class="rule-program">{{ rule.program }}</div>
</div>
<div>
<span :class="'direction-badge direction-' + rule.direction">
{{ rule.direction === 'inbound' ? '入站' : '出站' }}
</span>
</div>
<div>
<span :class="'action-badge action-' + rule.action">
{{ rule.action === 'allow' ? '允许' : '阻止' }}
</span>
</div>
<div>{{ rule.protocol }}/{{ rule.ports }}</div>
<div>
<span :class="'status-badge status-' + rule.status">
{{ rule.status === 'enabled' ? '已启用' : '已禁用' }}
</span>
</div>
<div>{{ rule.scope }}</div>
<div class="rule-actions">
<button class="icon-btn edit" @click="editRule(rule)" title="编辑">
<i data-lucide="edit"></i>
</button>
<button class="icon-btn toggle" @click="toggleRule(rule)" title="切换状态">
<i :data-lucide="rule.status === 'enabled' ? 'pause' : 'play'"></i>
</button>
<button class="icon-btn delete" @click="deleteRule(rule.id)" title="删除">
<i data-lucide="trash-2"></i>
</button>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal" :class="{ show: showModal }" @click.self="closeModal">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">{{ editingRule ? '编辑规则' : '新增规则' }}</h2>
<button class="close-btn" @click="closeModal">
<i data-lucide="x"></i>
</button>
</div>
<div class="modal-body">
<div class="tabs">
<div class="tab" :class="{ active: activeTab === 'general' }" @click="activeTab = 'general'">
常规
</div>
<div class="tab" :class="{ active: activeTab === 'programs' }" @click="activeTab = 'programs'">
程序和服务
</div>
<div class="tab" :class="{ active: activeTab === 'protocols' }" @click="activeTab = 'protocols'">
协议和端口
</div>
<div class="tab" :class="{ active: activeTab === 'scope' }" @click="activeTab = 'scope'">
作用域
</div>
<div class="tab" :class="{ active: activeTab === 'advanced' }" @click="activeTab = 'advanced'">
高级
</div>
</div>
<!-- 常规选项卡 -->
<div class="tab-content" :class="{ active: activeTab === 'general' }">
<div class="form-group">
<label class="form-label">规则名称</label>
<input type="text" v-model="formData.name" class="form-input" placeholder="输入规则名称">
</div>
<div class="form-group">
<label class="form-label">描述</label>
<textarea v-model="formData.description" class="form-textarea" placeholder="规则描述(可选)"></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">方向</label>
<select v-model="formData.direction" class="form-select">
<option value="inbound">入站</option>
<option value="outbound">出站</option>
</select>
</div>
<div class="form-group">
<label class="form-label">操作</label>
<select v-model="formData.action" class="form-select">
<option value="allow">允许连接</option>
<option value="block">阻止连接</option>
</select>
</div>
</div>
<div class="checkbox-group">
<input type="checkbox" v-model="formData.enabled" class="checkbox" id="enabled">
<label for="enabled">启用此规则</label>
</div>
</div>
<!-- 程序和服务选项卡 -->
<div class="tab-content" :class="{ active: activeTab === 'programs' }">
<div class="form-group">
<label class="form-label">应用程序</label>
<div class="checkbox-group">
<input type="radio" v-model="formData.programType" value="all" name="programType" id="all-programs">
<label for="all-programs">所有程序</label>
</div>
<div class="checkbox-group">
<input type="radio" v-model="formData.programType" value="specific" name="programType" id="specific-program">
<label for="specific-program">此程序路径:</label>
</div>
<input
type="text"
v-model="formData.programPath"
class="form-input"
placeholder="C:\Program Files\..."
:disabled="formData.programType !== 'specific'"
>
</div>
<div class="form-group">
<label class="form-label">服务</label>
<div class="checkbox-group">
<input type="radio" v-model="formData.serviceType" value="all" name="serviceType" id="all-services">
<label for="all-services">应用于所有程序和服务</label>
</div>
<div class="checkbox-group">
<input type="radio" v-model="formData.serviceType" value="specific" name="serviceType" id="specific-services">
<label for="specific-services">仅应用于这些服务:</label>
</div>
<div v-if="formData.serviceType === 'specific'" class="service-list">
<div v-for="service in availableServices" :key="service.name" class="service-item">
<input
type="checkbox"
:value="service.name"
v-model="formData.selectedServices"
:id="'service-' + service.name"
>
<label :for="'service-' + service.name">{{ service.displayName }}</label>
</div>
</div>
</div>
</div>
<!-- 协议和端口选项卡 -->
<div class="tab-content" :class="{ active: activeTab === 'protocols' }">
<div class="form-group">
<label class="form-label">协议类型</label>
<select v-model="formData.protocolType" class="form-select">
<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 v-if="formData.protocolType === 'custom'" class="form-group">
<label class="form-label">协议号</label>
<input type="number" v-model="formData.protocolNumber" class="form-input" placeholder="0-255">
</div>
<div v-if="['tcp', 'udp'].includes(formData.protocolType)" class="form-row">
<div class="form-group">
<label class="form-label">本地端口</label>
<div class="checkbox-group">
<input type="radio" v-model="formData.localPortType" value="all" name="localPortType" id="all-local-ports">
<label for="all-local-ports">所有端口</label>
</div>
<div class="checkbox-group">
<input type="radio" v-model="formData.localPortType" value="specific" name="localPortType" id="specific-local-ports">
<label for="specific-local-ports">特定端口:</label>
</div>
<input
type="text"
v-model="formData.localPorts"
class="form-input"
placeholder="80,443,8000-8080"
:disabled="formData.localPortType !== 'specific'"
>
</div>
<div class="form-group">
<label class="form-label">远程端口</label>
<div class="checkbox-group">
<input type="radio" v-model="formData.remotePortType" value="all" name="remotePortType" id="all-remote-ports">
<label for="all-remote-ports">所有端口</label>
</div>
<div class="checkbox-group">
<input type="radio" v-model="formData.remotePortType" value="specific" name="remotePortType" id="specific-remote-ports">
<label for="specific-remote-ports">特定端口:</label>
</div>
<input
type="text"
v-model="formData.remotePorts"
class="form-input"
placeholder="80,443,8000-8080"
:disabled="formData.remotePortType !== 'specific'"
>
</div>
</div>
</div>
<!-- 作用域选项卡 -->
<div class="tab-content" :class="{ active: activeTab === 'scope' }">
<div class="form-group">
<label class="form-label">本地IP地址</label>
<div class="checkbox-group">
<input type="radio" v-model="formData.localAddressType" value="any" name="localAddressType" id="any-local-address">
<label for="any-local-address">任何IP地址</label>
</div>
<div class="checkbox-group">
<input type="radio" v-model="formData.localAddressType" value="specific" name="localAddressType" id="specific-local-address">
<label for="specific-local-address">这些IP地址:</label>
</div>
<textarea
v-model="formData.localAddresses"
class="form-textarea"
placeholder="192.168.1.1&#10;10.0.0.0/8&#10;172.16.0.0-172.31.255.255"
:disabled="formData.localAddressType !== 'specific'"
></textarea>
</div>
<div class="form-group">
<label class="form-label">远程IP地址</label>
<div class="checkbox-group">
<input type="radio" v-model="formData.remoteAddressType" value="any" name="remoteAddressType" id="any-remote-address">
<label for="any-remote-address">任何IP地址</label>
</div>
<div class="checkbox-group">
<input type="radio" v-model="formData.remoteAddressType" value="specific" name="remoteAddressType" id="specific-remote-address">
<label for="specific-remote-address">这些IP地址:</label>
</div>
<textarea
v-model="formData.remoteAddresses"
class="form-textarea"
placeholder="8.8.8.8&#10;192.168.0.0/16&#10;203.0.113.0-203.0.113.255"
:disabled="formData.remoteAddressType !== 'specific'"
></textarea>
</div>
</div>
<!-- 高级选项卡 -->
<div class="tab-content" :class="{ active: activeTab === 'advanced' }">
<div class="form-group">
<label class="form-label">配置文件</label>
<div class="checkbox-group">
<input type="checkbox" v-model="formData.profiles.domain" id="profile-domain">
<label for="profile-domain">域</label>
</div>
<div class="checkbox-group">
<input type="checkbox" v-model="formData.profiles.private" id="profile-private">
<label for="profile-private">专用</label>
</div>
<div class="checkbox-group">
<input type="checkbox" v-model="formData.profiles.public" id="profile-public">
<label for="profile-public">公用</label>
</div>
</div>
<div class="form-group">
<label class="form-label">边缘遍历</label>
<select v-model="formData.edgeTraversal" class="form-select">
<option value="no">阻止边缘遍历</option>
<option value="allow">允许边缘遍历</option>
<option value="defer">延迟到用户</option>
<option value="defer-app">延迟到应用程序</option>
</select>
</div>
<div class="form-group">
<label class="form-label">授权用户</label>
<div class="checkbox-group">
<input type="radio" v-model="formData.userType" value="any" name="userType" id="any-user">
<label for="any-user">任何用户</label>
</div>
<div class="checkbox-group">
<input type="radio" v-model="formData.userType" value="specific" name="userType" id="specific-users">
<label for="specific-users">仅这些用户:</label>
</div>
<input
type="text"
v-model="formData.authorizedUsers"
class="form-input"
placeholder="DOMAIN\Username, Everyone, ..."
:disabled="formData.userType !== 'specific'"
>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" @click="closeModal">取消</button>
<button class="btn btn-success" @click="saveRule">
{{ editingRule ? '保存' : '创建' }}
</button>
</div>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
showModal: false,
editingRule: null,
activeTab: 'general',
searchText: '',
filterDirection: '',
filterAction: '',
filterStatus: '',
// 表单数据
formData: {
name: '',
description: '',
direction: 'inbound',
action: 'allow',
enabled: true,
programType: 'all',
programPath: '',
serviceType: 'all',
selectedServices: [],
protocolType: 'any',
protocolNumber: '',
localPortType: 'all',
localPorts: '',
remotePortType: 'all',
remotePorts: '',
localAddressType: 'any',
localAddresses: '',
remoteAddressType: 'any',
remoteAddresses: '',
profiles: {
domain: true,
private: true,
public: false
},
edgeTraversal: 'no',
userType: 'any',
authorizedUsers: ''
},
// 可用服务列表
availableServices: [
{ name: 'http', displayName: 'HTTP (80)' },
{ name: 'https', displayName: 'HTTPS (443)' },
{ name: 'ftp', displayName: 'FTP (21)' },
{ name: 'ssh', displayName: 'SSH (22)' },
{ name: 'telnet', displayName: 'Telnet (23)' },
{ name: 'smtp', displayName: 'SMTP (25)' },
{ name: 'dns', displayName: 'DNS (53)' },
{ name: 'dhcp', displayName: 'DHCP (67-68)' },
{ name: 'pop3', displayName: 'POP3 (110)' },
{ name: 'imap', displayName: 'IMAP (143)' },
{ name: 'snmp', displayName: 'SNMP (161)' },
{ name: 'ldap', displayName: 'LDAP (389)' },
{ name: 'smb', displayName: 'SMB (445)' },
{ name: 'rdp', displayName: 'RDP (3389)' }
],
// 防火墙规则数据
rules: [
{
id: 1,
name: 'Core Networking - DNS (UDP-Out)',
program: 'svchost.exe',
direction: 'outbound',
action: 'allow',
protocol: 'UDP',
ports: '53',
status: 'enabled',
scope: '任何'
},
{
id: 2,
name: 'Windows Remote Management (HTTP-In)',
program: 'svchost.exe',
direction: 'inbound',
action: 'allow',
protocol: 'TCP',
ports: '5985',
status: 'enabled',
scope: '本地子网'
},
{
id: 3,
name: 'File and Printer Sharing (SMB-In)',
program: 'System',
direction: 'inbound',
action: 'allow',
protocol: 'TCP',
ports: '445',
status: 'disabled',
scope: '专用'
},
{
id: 4,
name: 'Remote Desktop - User Mode (TCP-In)',
program: 'svchost.exe',
direction: 'inbound',
action: 'allow',
protocol: 'TCP',
ports: '3389',
status: 'enabled',
scope: '任何'
},
{
id: 5,
name: 'Block Suspicious Outbound',
program: 'malware.exe',
direction: 'outbound',
action: 'block',
protocol: 'TCP',
ports: '任何',
status: 'enabled',
scope: '任何'
},
{
id: 6,
name: 'Web Browser (HTTP/HTTPS-Out)',
program: 'chrome.exe',
direction: 'outbound',
action: 'allow',
protocol: 'TCP',
ports: '80,443',
status: 'enabled',
scope: '任何'
},
{
id: 7,
name: 'Email Client (SMTP-Out)',
program: 'outlook.exe',
direction: 'outbound',
action: 'allow',
protocol: 'TCP',
ports: '25,587',
status: 'disabled',
scope: '任何'
},
{
id: 8,
name: 'Windows Update (HTTP-Out)',
program: 'svchost.exe',
direction: 'outbound',
action: 'allow',
protocol: 'TCP',
ports: '80,443',
status: 'enabled',
scope: '任何'
}
]
}
},
computed: {
filteredRules() {
let filtered = this.rules;
if (this.searchText) {
filtered = filtered.filter(rule =>
rule.name.toLowerCase().includes(this.searchText.toLowerCase()) ||
rule.program.toLowerCase().includes(this.searchText.toLowerCase())
);
}
if (this.filterDirection) {
filtered = filtered.filter(rule => rule.direction === this.filterDirection);
}
if (this.filterAction) {
filtered = filtered.filter(rule => rule.action === this.filterAction);
}
if (this.filterStatus) {
filtered = filtered.filter(rule => rule.status === this.filterStatus);
}
return filtered;
},
totalRules() {
return this.rules.length;
},
enabledRules() {
return this.rules.filter(rule => rule.status === 'enabled').length;
},
disabledRules() {
return this.rules.filter(rule => rule.status === 'disabled').length;
}
},
methods: {
openModal(rule = null) {
this.editingRule = rule;
this.activeTab = 'general';
if (rule) {
// 编辑模式 - 填充表单数据
this.formData = {
name: rule.name,
description: '',
direction: rule.direction,
action: rule.action,
enabled: rule.status === 'enabled',
programType: 'all',
programPath: rule.program,
serviceType: 'all',
selectedServices: [],
protocolType: rule.protocol.toLowerCase(),
protocolNumber: '',
localPortType: 'specific',
localPorts: rule.ports,
remotePortType: 'all',
remotePorts: '',
localAddressType: 'any',
localAddresses: '',
remoteAddressType: 'any',
remoteAddresses: '',
profiles: {
domain: true,
private: true,
public: false
},
edgeTraversal: 'no',
userType: 'any',
authorizedUsers: ''
};
} else {
// 新增模式 - 重置表单
this.resetForm();
}
this.showModal = true;
},
closeModal() {
this.showModal = false;
this.editingRule = null;
this.resetForm();
},
resetForm() {
this.formData = {
name: '',
description: '',
direction: 'inbound',
action: 'allow',
enabled: true,
programType: 'all',
programPath: '',
serviceType: 'all',
selectedServices: [],
protocolType: 'any',
protocolNumber: '',
localPortType: 'all',
localPorts: '',
remotePortType: 'all',
remotePorts: '',
localAddressType: 'any',
localAddresses: '',
remoteAddressType: 'any',
remoteAddresses: '',
profiles: {
domain: true,
private: true,
public: false
},
edgeTraversal: 'no',
userType: 'any',
authorizedUsers: ''
};
},
saveRule() {
if (!this.formData.name.trim()) {
alert('请输入规则名称');
return;
}
const ruleData = {
name: this.formData.name,
program: this.formData.programType === 'specific' ? this.formData.programPath : 'System',
direction: this.formData.direction,
action: this.formData.action,
protocol: this.formData.protocolType.toUpperCase(),
ports: this.formData.localPortType === 'specific' ? this.formData.localPorts : '任何',
status: this.formData.enabled ? 'enabled' : 'disabled',
scope: '任何'
};
if (this.editingRule) {
// 编辑现有规则
const index = this.rules.findIndex(rule => rule.id === this.editingRule.id);
if (index !== -1) {
this.rules[index] = { ...this.rules[index], ...ruleData };
}
} else {
// 新增规则
const newRule = {
id: Math.max(...this.rules.map(r => r.id)) + 1,
...ruleData
};
this.rules.push(newRule);
}
this.closeModal();
},
editRule(rule) {
this.openModal(rule);
},
toggleRule(rule) {
rule.status = rule.status === 'enabled' ? 'disabled' : 'enabled';
},
deleteRule(ruleId) {
if (confirm('确定要删除这个规则吗?')) {
this.rules = this.rules.filter(rule => rule.id !== ruleId);
}
}
},
mounted() {
// 初始化Lucide图标
lucide.createIcons();
},
updated() {
// 更新时重新创建图标
lucide.createIcons();
}
}).mount('#app');
</script>
</body>
</html>