Files
mce/templates/MetaLab-2026/html/messages/index.html
Victor_Jay d3e5cbe18b refactor: 静态资源缓存破坏改为文件级哈希,重启不刷新未修改文件的缓存
- 启动时计算每个 JS/CSS 的 SHA-1 前 8 位作为版本号
- 文件不变则哈希不变,浏览器继续用缓存,重启零压力
- 替换全局 AssetVersion 为 assetV 模板函数,按文件路径查询哈希
- 移除 BuildPageData 中的全局版本号注入
2026-05-31 01:53:17 +08:00

208 lines
8.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{{template "layout/header.html" .}}
<meta name="robots" content="noindex,nofollow">
<body>
{{template "layout/nav.html" .}}
<main class="msg-layout">
<aside class="msg-sidebar">
<div class="msg-sidebar-header">
<h2>消息中心</h2>
</div>
<nav class="msg-sidebar-nav">
<span class="msg-sidebar-item active">
<svg class="msg-sidebar-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
全部消息
{{if .UnreadCount}}
<span class="msg-sidebar-count">{{.UnreadCount}}</span>
{{end}}
</span>
</nav>
</aside>
<div class="msg-main">
<!-- 系统消息区域 -->
<div class="msg-system-section">
<div class="msg-system-header">
<svg class="msg-system-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
系统消息
</div>
<div class="msg-system-divider"></div>
</div>
{{if .Messages}}
<div class="msg-toolbar">
{{if .UnreadCount}}
<button id="markAllReadBtn" class="msg-mark-all-btn">全部标为已读</button>
{{end}}
</div>
<div class="msg-list">
{{range $i, $m := .Messages}}
{{$link := ""}}
{{if or (eq $m.NotifyType "post_approved") (eq $m.NotifyType "post_rejected")}}
{{if eq $m.NotifyType "post_approved"}}
{{$link = printf "/posts/%d" $m.RelatedID}}
{{else}}
{{$link = "/studio/posts"}}
{{end}}
{{end}}
{{if $link}}
<a href="{{$link}}" class="msg-card-link">
{{end}}
<div class="msg-card{{if not $m.IsRead}} unread{{end}}" data-id="{{$m.ID}}" data-type="{{$m.NotifyType}}" data-link="{{$link}}">
<div class="msg-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="20" height="20"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
</div>
<div class="msg-body">
<div class="msg-title">{{$m.Title}}</div>
<div class="msg-content">{{$m.Content}}</div>
<div class="msg-meta">
<span class="msg-type">{{index $.NotifyTypeNames $m.NotifyType}}</span>
<span class="msg-time">{{$m.CreatedAt.Format "2006-01-02 15:04"}}</span>
</div>
</div>
{{if not $m.IsRead}}
<span class="msg-badge"></span>
{{end}}
</div>
{{if $link}}
</a>
{{end}}
{{end}}
</div>
{{if .TotalPages}}
<div class="msg-pagination">
{{if .HasPrev}}
<a href="/messages?page={{.PrevPage}}" class="msg-page-btn">上一页</a>
{{else}}
<span class="msg-page-btn disabled">上一页</span>
{{end}}
<span class="msg-page-info">{{.Page}} / {{.TotalPages}}</span>
{{if .HasNext}}
<a href="/messages?page={{.NextPage}}" class="msg-page-btn">下一页</a>
{{else}}
<span class="msg-page-btn disabled">下一页</span>
{{end}}
</div>
{{end}}
{{else}}
<div class="msg-empty">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="48" height="48" class="msg-empty-icon"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><line x1="4" y1="17" x2="20" y2="17"/><line x1="9" y1="11" x2="10" y2="11"/><line x1="14" y1="11" x2="15" y2="11"/></svg>
<p>暂无消息</p>
</div>
{{end}}
</div>
</main>
{{template "layout/footer.html" .}}
<script>
(function () {
'use strict';
// ---- 单条标记已读 ----
var cards = document.querySelectorAll('.msg-card.unread');
for (var i = 0; i < cards.length; i++) {
(function (card) {
card.addEventListener('click', function (e) {
var link = card.getAttribute('data-link');
// 如果是可跳转的通知post 审核),不阻止默认行为,只标记已读
// 标记已读通过 fetch 发送,不阻止链接跳转
var id = card.getAttribute('data-id');
if (!id) return;
var xhr = new XMLHttpRequest();
xhr.open('POST', '/api/messages/' + id + '/read', true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
card.classList.remove('unread');
var badge = card.querySelector('.msg-badge');
if (badge) badge.remove();
updateUnreadCounts();
}
};
xhr.send();
// 如果有链接,在标记已读后跳转(非 post 通知直接标记已读)
if (link) {
e.preventDefault();
var self = this;
setTimeout(function () {
window.location.href = link;
}, 200);
}
});
})(cards[i]);
}
// ---- 全部标为已读 ----
var markAllBtn = document.getElementById('markAllReadBtn');
if (markAllBtn) {
markAllBtn.addEventListener('click', function () {
markAllBtn.disabled = true;
markAllBtn.textContent = '处理中...';
var xhr = new XMLHttpRequest();
xhr.open('POST', '/api/messages/read-all', true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
markAllBtn.disabled = false;
markAllBtn.textContent = '全部标为已读';
if (xhr.status === 200) {
// 本地清除所有 unread 样式
var allCards = document.querySelectorAll('.msg-card.unread');
for (var j = 0; j < allCards.length; j++) {
allCards[j].classList.remove('unread');
var b = allCards[j].querySelector('.msg-badge');
if (b) b.remove();
}
markAllBtn.remove();
updateUnreadCounts();
}
}
};
xhr.send();
});
}
// ---- 更新侧边栏和导航栏未读计数 ----
function updateUnreadCounts() {
// 更新侧边栏计数
var visibleUnread = document.querySelectorAll('.msg-card.unread').length;
var sidebarCount = document.querySelector('.msg-sidebar-count');
if (sidebarCount) {
if (visibleUnread > 0) {
sidebarCount.textContent = visibleUnread;
} else {
sidebarCount.remove();
}
} else if (visibleUnread > 0) {
var sidebarItem = document.querySelector('.msg-sidebar-item.active');
if (sidebarItem) {
var el = document.createElement('span');
el.className = 'msg-sidebar-count';
el.textContent = visibleUnread;
sidebarItem.appendChild(el);
}
}
// 更新导航栏铃铛计数
var navBadge = document.getElementById('msgBadge');
if (navBadge) {
fetch('/api/messages/unread')
.then(function (res) { return res.json(); })
.then(function (data) {
if (data && data.success && data.data) {
var count = data.data.unread || 0;
navBadge.textContent = count > 99 ? '99+' : count;
navBadge.style.display = count > 0 ? 'flex' : 'none';
}
})
.catch(function () {});
}
}
})();
</script>
<script src="/static/js/common.js?v={{assetV "/static/js/common.js"}}"></script>
</body>
</html>