feat: 前端整体重写为 QQ 邮箱风格布局
- base.html: 全新设计系统(顶部导航栏 + 左侧文件夹栏 + 内容区三栏布局, 蓝/橙主题色),兼容管理后台原有组件类 - inbox/drafts/sent: 邮件列表页重写,支持全选、批量删除、实时搜索过滤、 未读标记、头像圆标、QQ 式短日期、悬停行内删除、分页 - view: 邮件阅读页重写(返回/回复/删除工具条、发件人卡片、附件区) - compose: 写信页重写(发送/附件/取消、字段行、附件 chips、配额进度条) - settings/login/banned: 设置页(账号信息+配额条)、登录页、封禁页重写 - server.go: 新增模板函数 mailName/mailEmail/initial/truncate/shortDate/avatarStyle - mail.go: 侧栏文件夹计数(收件箱未读红标、草稿/已发送数量) - 新增 render_test.go 模板渲染回归测试
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package web
|
||||
|
||||
// Temporary render test used to validate the rewritten frontend templates.
|
||||
// Renders every page template with realistic dummy data and writes the
|
||||
// output to /tmp/mailgo_preview for visual verification.
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"mail_go/internal/db"
|
||||
)
|
||||
|
||||
func TestRenderAllPages(t *testing.T) {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tmpl := template.Must(template.New("").Funcs(templateFuncs()).ParseGlob(filepath.Join(wd, "templates", "*.html")))
|
||||
template.Must(tmpl.ParseGlob(filepath.Join(wd, "templates", "admin", "*.html")))
|
||||
|
||||
now := time.Now()
|
||||
user := &db.User{
|
||||
ID: 1,
|
||||
Username: "admin",
|
||||
IsAdmin: true,
|
||||
Domain: db.Domain{Name: "lmve.net"},
|
||||
UsedBytes: 5 * 1024 * 1024,
|
||||
QuotaBytes: 5 * 1024 * 1024 * 1024,
|
||||
}
|
||||
|
||||
messages := []db.Message{
|
||||
{ID: 1, Folder: "INBOX", FromAddr: "=?UTF-8?B?5byg5LiJ?= <zhangsan@lmve.net>", ToAddr: "admin@lmve.net", Subject: "邮件系统部署完成通知", TextBody: "您好!您的 MailGo 邮件系统已成功部署,本邮件为测试邮件。", Date: now, IsRead: false},
|
||||
{ID: 2, Folder: "INBOX", FromAddr: "alice@example.com", ToAddr: "admin@lmve.net", Subject: "Re: 项目进度同步", TextBody: "好的,我们下周一上午十点开会同步一下进度。", Date: now.Add(-3 * time.Hour), IsRead: true},
|
||||
{ID: 3, Folder: "INBOX", FromAddr: "=?UTF-8?B?6ZmI5rKz?= <wangwu@lmve.net>", ToAddr: "admin@lmve.net", Subject: "服务器巡检报告(8 月)", TextBody: "本月巡检完成,磁盘使用率 62%,内存使用正常。", Date: now.Add(-48 * time.Hour), IsRead: false},
|
||||
{ID: 4, Folder: "INBOX", FromAddr: "bob@other.com", ToAddr: "admin@lmve.net", Subject: "Newsletter #42", TextBody: "这是本周的资讯摘要,共 5 篇文章。", Date: now.Add(-10 * 24 * time.Hour), IsRead: true},
|
||||
{ID: 5, Folder: "INBOX", FromAddr: "=?UTF-8?B?6ZmI5rKz?= <wangwu@lmve.net>", ToAddr: "admin@lmve.net", Subject: "DNS 记录更新", TextBody: "已按文档更新 SPF 与 DKIM 记录,请验证。", Date: now.Add(-100 * 24 * time.Hour), IsRead: true},
|
||||
}
|
||||
|
||||
attachments := []db.Attachment{
|
||||
{ID: 1, FileName: "部署文档.pdf", FileSize: 1024 * 1024},
|
||||
{ID: 2, FileName: "logo.png", FileSize: 128 * 1024},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
data ginH
|
||||
}{
|
||||
{"login", ginH{"error": ""}},
|
||||
{"banned", ginH{"entry": &db.BanEntry{IPAddress: "1.2.3.4", Reason: "登录失败次数过多", FailCount: 8, ExpiresAt: now.Add(20 * time.Minute)}}},
|
||||
{"inbox", ginH{"currentUser": user, "messages": messages, "total": 5, "page": 1, "totalPages": 1, "activeFolder": "inbox", "inboxUnread": int64(2), "draftsTotal": int64(1), "sentTotal": int64(3)}},
|
||||
{"drafts", ginH{"currentUser": user, "messages": messages, "total": 1, "page": 1, "totalPages": 1, "activeFolder": "drafts", "inboxUnread": int64(2), "draftsTotal": int64(1), "sentTotal": int64(3)}},
|
||||
{"sent", ginH{"currentUser": user, "messages": messages, "total": 3, "page": 1, "totalPages": 1, "activeFolder": "sent", "inboxUnread": int64(2), "draftsTotal": int64(1), "sentTotal": int64(3)}},
|
||||
{"view", ginH{
|
||||
"currentUser": user, "activeFolder": "inbox",
|
||||
"message": &db.Message{ID: 1, Folder: "INBOX", FromAddr: "=?UTF-8?B?5byg5LiJ?= <zhangsan@lmve.net>", ToAddr: "admin@lmve.net", Subject: "邮件系统部署完成通知", TextBody: "您好!您的 MailGo 邮件系统已成功部署。", HtmlBody: "", Date: now, IsRead: false},
|
||||
"attachments": attachments, "inboxUnread": int64(2), "draftsTotal": int64(1), "sentTotal": int64(3),
|
||||
}},
|
||||
{"compose", ginH{
|
||||
"currentUser": user, "activeFolder": "compose", "error": "",
|
||||
"to": "zhangsan@lmve.net", "subject": "Re: 邮件系统部署完成通知", "bodyContent": "",
|
||||
"usedBytes": int64(5 * 1024 * 1024), "quotaBytes": int64(5 * 1024 * 1024 * 1024),
|
||||
"inboxUnread": int64(2), "draftsTotal": int64(1), "sentTotal": int64(3),
|
||||
}},
|
||||
{"settings", ginH{"currentUser": user, "activeFolder": "settings", "error": "", "success": "", "inboxUnread": int64(2), "draftsTotal": int64(1), "sentTotal": int64(3)}},
|
||||
{"admin_dashboard", ginH{"currentUser": user, "activeFolder": "admin", "domainCount": 2, "userCount": 5, "totalMails": 100, "banCount": 1, "inboxCount": 50, "sentCount": 30, "draftsCount": 10, "trashCount": 5, "inboxSize": int64(1024), "sentSize": int64(512), "totalSize": int64(2048), "todayReceived": 3, "todaySent": 2, "weekReceived": 20, "weekSent": 15}},
|
||||
}
|
||||
|
||||
outDir := os.Getenv("MAILGO_PREVIEW_DIR")
|
||||
if outDir == "" {
|
||||
outDir = filepath.Join(os.TempDir(), "mailgo_preview")
|
||||
}
|
||||
os.MkdirAll(outDir, 0755)
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var buf strings.Builder
|
||||
if err := tmpl.ExecuteTemplate(&buf, tc.name, tc.data); err != nil {
|
||||
t.Fatalf("render %s: %v", tc.name, err)
|
||||
}
|
||||
os.WriteFile(filepath.Join(outDir, tc.name+".html"), []byte(buf.String()), 0644)
|
||||
t.Logf("%s -> %d bytes", tc.name, buf.Len())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ginH mimics gin.H so the test does not need the gin dependency surface.
|
||||
type ginH map[string]interface{}
|
||||
Reference in New Issue
Block a user