二阶段差不多

This commit is contained in:
2026-06-01 19:46:51 +08:00
parent 9e50d05e71
commit 4e233c82b4
34 changed files with 1631 additions and 67 deletions
+80
View File
@@ -0,0 +1,80 @@
{{define "admin_bans"}}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IP黑名单 - MailGo</title>
{{template "styles" .}}
</head>
<body>
{{template "navbar" .}}
<div class="container">
<div class="clearfix">
<div class="sidebar">
<a href="/inbox">返回邮箱</a>
<a href="/admin" {{if eq .activeFolder "admin"}}class="active"{{end}}>控制面板</a>
<a href="/admin/domains" {{if eq .activeFolder "domains"}}class="active"{{end}}>域名管理</a>
<a href="/admin/users" {{if eq .activeFolder "users"}}class="active"{{end}}>用户管理</a>
<a href="/admin/mails" {{if eq .activeFolder "mails"}}class="active"{{end}}>所有邮件</a>
<a href="/admin/bans" {{if eq .activeFolder "bans"}}class="active"{{end}}>IP黑名单</a>
</div>
<div class="content">
<div class="card">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;">
<h2>IP 黑名单</h2>
<form method="POST" action="/admin/bans/cleanup" style="display:inline;">
<button type="submit" class="btn btn-primary">清理过期记录</button>
</form>
</div>
{{if not .bans}}
<p style="color:#7f8c8d;text-align:center;padding:40px 0;">暂无被封禁的 IP</p>
{{else}}
<table>
<thead>
<tr>
<th>ID</th>
<th>IP 地址</th>
<th>失败次数</th>
<th>原因</th>
<th>到期时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{range .bans}}
<tr>
<td>{{.ID}}</td>
<td>{{.IPAddress}}</td>
<td>{{.FailCount}}</td>
<td>{{.Reason}}</td>
<td>{{.ExpiresAt.Format "2006-01-02 15:04:05"}}</td>
<td>
<form method="POST" action="/admin/bans/{{.ID}}/unban" style="display:inline;"
onsubmit="return confirm('确定要解封 IP {{.IPAddress}} 吗?');">
<button type="submit" class="btn btn-primary btn-sm">解封</button>
</form>
</td>
</tr>
{{end}}
</tbody>
</table>
{{end}}
</div>
{{if .totalPages}}
<div class="pagination">
{{if gt .page 1}}
<a href="/admin/bans?page={{sub .page 1}}">上一页</a>
{{end}}
<span>第 {{.page}} / {{.totalPages}} 页</span>
{{if lt .page .totalPages}}
<a href="/admin/bans?page={{add .page 1}}">下一页</a>
{{end}}
</div>
{{end}}
</div>
</div>
</div>
</body>
</html>
{{end}}
+46 -3
View File
@@ -13,9 +13,11 @@
<div class="clearfix">
<div class="sidebar">
<a href="/inbox">返回邮箱</a>
<a href="/admin" class="active">控制面板</a>
<a href="/admin/domains">域名管理</a>
<a href="/admin/users">用户管理</a>
<a href="/admin" {{if eq .activeFolder "admin"}}class="active"{{end}}>控制面板</a>
<a href="/admin/domains" {{if eq .activeFolder "domains"}}class="active"{{end}}>域名管理</a>
<a href="/admin/users" {{if eq .activeFolder "users"}}class="active"{{end}}>用户管理</a>
<a href="/admin/mails" {{if eq .activeFolder "mails"}}class="active"{{end}}>所有邮件</a>
<a href="/admin/bans" {{if eq .activeFolder "bans"}}class="active"{{end}}>IP黑名单</a>
</div>
<div class="content">
<h2 style="margin-bottom:24px;">管理后台</h2>
@@ -28,12 +30,53 @@
<h3>{{.userCount}}</h3>
<p>用户数</p>
</div>
<div class="stat-card">
<h3>{{.totalMails}}</h3>
<p>邮件总数</p>
</div>
<div class="stat-card">
<h3>{{.banCount}}</h3>
<p>被封IP</p>
</div>
</div>
<div class="card">
<h3>邮件分布</h3>
<table style="margin-top:12px;">
<thead>
<tr>
<th>文件夹</th>
<th>邮件数</th>
<th>占用空间</th>
</tr>
</thead>
<tbody>
<tr><td>收件箱 (INBOX)</td><td>{{.inboxCount}}</td><td>{{formatBytes .inboxSize}}</td></tr>
<tr><td>发件箱 (Sent)</td><td>{{.sentCount}}</td><td>{{formatBytes .sentSize}}</td></tr>
<tr><td>草稿箱 (Drafts)</td><td>{{.draftsCount}}</td><td></td></tr>
<tr><td>垃圾箱 (Trash)</td><td>{{.trashCount}}</td><td></td></tr>
<tr style="font-weight:bold;"><td>合计</td><td>{{.totalMails}}</td><td>{{formatBytes .totalSize}}</td></tr>
</tbody>
</table>
</div>
<div class="card">
<h3>收发统计</h3>
<table style="margin-top:12px;">
<thead>
<tr><th>时间段</th><th>收件</th><th>发件</th></tr>
</thead>
<tbody>
<tr><td>今日</td><td>{{.todayReceived}}</td><td>{{.todaySent}}</td></tr>
<tr><td>近 7 天</td><td>{{.weekReceived}}</td><td>{{.weekSent}}</td></tr>
</tbody>
</table>
</div>
<div class="card">
<h3>快捷操作</h3>
<p style="margin-top:12px;">
<a href="/admin/domains/new" class="btn btn-primary">新增域名</a>
<a href="/admin/users/new" class="btn btn-primary" style="margin-left:8px;">新增用户</a>
<a href="/admin/mails" class="btn btn-primary" style="margin-left:8px;">查看所有邮件</a>
<a href="/admin/bans" class="btn btn-primary" style="margin-left:8px;">IP黑名单</a>
</p>
</div>
</div>
+11 -5
View File
@@ -13,9 +13,11 @@
<div class="clearfix">
<div class="sidebar">
<a href="/inbox">返回邮箱</a>
<a href="/admin">控制面板</a>
<a href="/admin/domains" class="active">域名管理</a>
<a href="/admin/users">用户管理</a>
<a href="/admin" {{if eq .activeFolder "admin"}}class="active"{{end}}>控制面板</a>
<a href="/admin/domains" {{if eq .activeFolder "domains"}}class="active"{{end}}>域名管理</a>
<a href="/admin/users" {{if eq .activeFolder "users"}}class="active"{{end}}>用户管理</a>
<a href="/admin/mails" {{if eq .activeFolder "mails"}}class="active"{{end}}>所有邮件</a>
<a href="/admin/bans" {{if eq .activeFolder "bans"}}class="active"{{end}}>IP黑名单</a>
</div>
<div class="content">
<div class="card">
@@ -28,8 +30,12 @@
<h4 style="margin-bottom:8px;">SPF 记录 (TXT)</h4>
<div class="dns-record">@ IN TXT "v=spf1 mx -all"</div>
<h4 style="margin-bottom:8px;">DKIM 记录</h4>
<div class="dns-record" style="color:#e67e22;">⚠️ 请在域名配置页配置 DKIM 私钥路径后,将自动生成 DKIM 公钥记录。</div>
<h4 style="margin-bottom:8px;">DKIM 记录 (TXT)</h4>
{{if .domain.DkimPublicKey}}
<div class="dns-record">default._domainkey.{{.domain.Name}}. IN TXT "{{.dkimRecord}}"</div>
{{else}}
<div class="dns-record" style="color:#e67e22;">⚠️ DKIM 密钥尚未生成,请编辑域名重新生成。</div>
{{end}}
<h4 style="margin-bottom:8px;">DMARC 记录</h4>
<div class="dns-record">_dmarc.{{.domain.Name}}. IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@{{.domain.Name}}"</div>
+22 -3
View File
@@ -13,9 +13,11 @@
<div class="clearfix">
<div class="sidebar">
<a href="/inbox">返回邮箱</a>
<a href="/admin">控制面板</a>
<a href="/admin/domains" class="active">域名管理</a>
<a href="/admin/users">用户管理</a>
<a href="/admin" {{if eq .activeFolder "admin"}}class="active"{{end}}>控制面板</a>
<a href="/admin/domains" {{if eq .activeFolder "domains"}}class="active"{{end}}>域名管理</a>
<a href="/admin/users" {{if eq .activeFolder "users"}}class="active"{{end}}>用户管理</a>
<a href="/admin/mails" {{if eq .activeFolder "mails"}}class="active"{{end}}>所有邮件</a>
<a href="/admin/bans" {{if eq .activeFolder "bans"}}class="active"{{end}}>IP黑名单</a>
</div>
<div class="content">
<div class="card">
@@ -24,7 +26,11 @@
<form method="POST" action="{{if .isEdit}}/admin/domains/{{.domain.ID}}{{else}}/admin/domains{{end}}">
<div class="form-group">
<label>域名</label>
{{if .isEdit}}
<input type="text" name="name" value="{{.domain.Name}}" disabled style="background:#f5f5f5;">
{{else}}
<input type="text" name="name" required value="{{.domain.Name}}" placeholder="example.com">
{{end}}
</div>
<div class="form-group">
<label>SMTP 端口</label>
@@ -44,6 +50,19 @@
启用 TLS
</label>
</div>
{{if .isEdit}}
<div class="form-group">
<label>
<input type="checkbox" name="regenerate_dkim">
重新生成 DKIM 密钥
</label>
{{if .domain.DkimPublicKey}}
<p style="color:#27ae60;font-size:12px;margin-top:4px;">✅ DKIM 密钥已配置</p>
{{else}}
<p style="color:#e67e22;font-size:12px;margin-top:4px;">⚠️ DKIM 密钥未配置</p>
{{end}}
</div>
{{end}}
<button type="submit" class="btn btn-primary">{{if .isEdit}}保存更改{{else}}创建域名{{end}}</button>
<a href="/admin/domains" class="btn" style="margin-left:8px;background:#bdc3c7;color:#fff;">取消</a>
</form>
+6 -3
View File
@@ -13,9 +13,11 @@
<div class="clearfix">
<div class="sidebar">
<a href="/inbox">返回邮箱</a>
<a href="/admin">控制面板</a>
<a href="/admin/domains" class="active">域名管理</a>
<a href="/admin/users">用户管理</a>
<a href="/admin" {{if eq .activeFolder "admin"}}class="active"{{end}}>控制面板</a>
<a href="/admin/domains" {{if eq .activeFolder "domains"}}class="active"{{end}}>域名管理</a>
<a href="/admin/users" {{if eq .activeFolder "users"}}class="active"{{end}}>用户管理</a>
<a href="/admin/mails" {{if eq .activeFolder "mails"}}class="active"{{end}}>所有邮件</a>
<a href="/admin/bans" {{if eq .activeFolder "bans"}}class="active"{{end}}>IP黑名单</a>
</div>
<div class="content">
<div class="card">
@@ -48,6 +50,7 @@
<td>{{.Pop3Port}}</td>
<td>{{if .TlsEnabled}}✅{{else}}❌{{end}}</td>
<td>
<a href="/admin/domains/{{.ID}}/edit" class="btn btn-primary btn-sm">编辑</a>
<a href="/admin/domains/{{.ID}}/dns" class="btn btn-primary btn-sm">DNS</a>
<form method="POST" action="/admin/domains/{{.ID}}/delete" style="display:inline;"
onsubmit="return confirm('确定要删除域名 {{.Name}} 吗?删除域名将导致关联用户无法收发邮件!');">
+77
View File
@@ -0,0 +1,77 @@
{{define "admin_mails"}}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>所有邮件 - MailGo</title>
{{template "styles" .}}
</head>
<body>
{{template "navbar" .}}
<div class="container">
<div class="clearfix">
<div class="sidebar">
<a href="/inbox">返回邮箱</a>
<a href="/admin" {{if eq .activeFolder "admin"}}class="active"{{end}}>控制面板</a>
<a href="/admin/domains" {{if eq .activeFolder "domains"}}class="active"{{end}}>域名管理</a>
<a href="/admin/users" {{if eq .activeFolder "users"}}class="active"{{end}}>用户管理</a>
<a href="/admin/mails" {{if eq .activeFolder "mails"}}class="active"{{end}}>所有邮件</a>
<a href="/admin/bans" {{if eq .activeFolder "bans"}}class="active"{{end}}>IP黑名单</a>
</div>
<div class="content">
<div class="card">
<h2 style="margin-bottom:16px;">所有邮件</h2>
<div style="margin-bottom:16px;">
<a href="/admin/mails" {{if eq .folder ""}}class="btn btn-primary"{{else}}class="btn" style="background:#ecf0f1;color:#333;"{{end}}>全部</a>
<a href="/admin/mails?folder=INBOX" {{if eq .folder "INBOX"}}class="btn btn-primary"{{else}}class="btn" style="background:#ecf0f1;color:#333;"{{end}}>INBOX</a>
<a href="/admin/mails?folder=Sent" {{if eq .folder "Sent"}}class="btn btn-primary"{{else}}class="btn" style="background:#ecf0f1;color:#333;"{{end}}>Sent</a>
<a href="/admin/mails?folder=Drafts" {{if eq .folder "Drafts"}}class="btn btn-primary"{{else}}class="btn" style="background:#ecf0f1;color:#333;"{{end}}>Drafts</a>
<a href="/admin/mails?folder=Trash" {{if eq .folder "Trash"}}class="btn btn-primary"{{else}}class="btn" style="background:#ecf0f1;color:#333;"{{end}}>Trash</a>
</div>
{{if not .messages}}
<p style="color:#7f8c8d;text-align:center;padding:40px 0;">暂无邮件</p>
{{else}}
<table>
<thead>
<tr>
<th>发件人</th>
<th>收件人</th>
<th>主题</th>
<th>所属用户</th>
<th>文件夹</th>
<th>日期</th>
</tr>
</thead>
<tbody>
{{range .messages}}
<tr>
<td>{{.FromAddr}}</td>
<td>{{.ToAddr}}</td>
<td>{{.Subject}}</td>
<td>{{if .User.ID}}{{.User.Username}}{{else}}—{{end}}</td>
<td>{{.Folder}}</td>
<td>{{.Date.Format "2006-01-02 15:04"}}</td>
</tr>
{{end}}
</tbody>
</table>
{{end}}
</div>
{{if .totalPages}}
<div class="pagination">
{{if gt .page 1}}
<a href="/admin/mails?page={{sub .page 1}}{{if .folder}}&folder={{.folder}}{{end}}">上一页</a>
{{end}}
<span>第 {{.page}} / {{.totalPages}} 页</span>
{{if lt .page .totalPages}}
<a href="/admin/mails?page={{add .page 1}}{{if .folder}}&folder={{.folder}}{{end}}">下一页</a>
{{end}}
</div>
{{end}}
</div>
</div>
</div>
</body>
</html>
{{end}}
+5 -3
View File
@@ -13,9 +13,11 @@
<div class="clearfix">
<div class="sidebar">
<a href="/inbox">返回邮箱</a>
<a href="/admin">控制面板</a>
<a href="/admin/domains">域名管理</a>
<a href="/admin/users" class="active">用户管理</a>
<a href="/admin" {{if eq .activeFolder "admin"}}class="active"{{end}}>控制面板</a>
<a href="/admin/domains" {{if eq .activeFolder "domains"}}class="active"{{end}}>域名管理</a>
<a href="/admin/users" {{if eq .activeFolder "users"}}class="active"{{end}}>用户管理</a>
<a href="/admin/mails" {{if eq .activeFolder "mails"}}class="active"{{end}}>所有邮件</a>
<a href="/admin/bans" {{if eq .activeFolder "bans"}}class="active"{{end}}>IP黑名单</a>
</div>
<div class="content">
<div class="card">
+5 -3
View File
@@ -13,9 +13,11 @@
<div class="clearfix">
<div class="sidebar">
<a href="/inbox">返回邮箱</a>
<a href="/admin">控制面板</a>
<a href="/admin/domains">域名管理</a>
<a href="/admin/users" class="active">用户管理</a>
<a href="/admin" {{if eq .activeFolder "admin"}}class="active"{{end}}>控制面板</a>
<a href="/admin/domains" {{if eq .activeFolder "domains"}}class="active"{{end}}>域名管理</a>
<a href="/admin/users" {{if eq .activeFolder "users"}}class="active"{{end}}>用户管理</a>
<a href="/admin/mails" {{if eq .activeFolder "mails"}}class="active"{{end}}>所有邮件</a>
<a href="/admin/bans" {{if eq .activeFolder "bans"}}class="active"{{end}}>IP黑名单</a>
</div>
<div class="content">
<div class="card">