- shared/utils.js 新增 showConfirm()/showPrompt() 通用函数(inline CSS,无需额外样式) - admin/common.js 移除重复 showConfirm(),统一使用 utils.js - admin/posts.js: 3 处 confirm/prompt 替换(审核/退回/锁定) - admin/comments.js: 1 处 confirm 替换 - settings/index.html: 4 处 confirm + 1 处 prompt 替换 - studio/posts.html + drafts.html: 3 处 confirm 替换 - post-view.js + login.js + post-favorite.js: 3 处 confirm 替换
116 lines
4.6 KiB
HTML
116 lines
4.6 KiB
HTML
{{template "layout/header.html" .}}
|
||
<body>
|
||
|
||
{{template "layout/nav.html" .}}
|
||
|
||
<div class="studio-wrapper">
|
||
{{template "studio/sidebar.html" .}}
|
||
|
||
<main class="studio-main">
|
||
<div class="studio-header">
|
||
<h1>内容管理</h1>
|
||
{{if .Overview}}
|
||
<div class="header-counts">
|
||
<span class="header-count approved">已发布 {{.Overview.ApprovedCount}}</span>
|
||
<span class="header-count pending">审核中 {{.Overview.PendingCount}}</span>
|
||
<span class="header-count draft">草稿 {{.Overview.DraftCount}}</span>
|
||
<span class="header-count rejected">已退回 {{.Overview.RejectedCount}}</span>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
{{if .Error}}
|
||
<div class="studio-error">{{.Error}}</div>
|
||
{{else}}
|
||
<!-- 状态筛选 tabs -->
|
||
<div class="status-tabs">
|
||
<a href="/studio/posts" class="status-tab {{if not .CurrentStatus}}active{{end}}">全部</a>
|
||
<a href="/studio/posts?status=approved" class="status-tab {{if eq .CurrentStatus "approved"}}active{{end}}">已发布</a>
|
||
<a href="/studio/posts?status=pending" class="status-tab {{if eq .CurrentStatus "pending"}}active{{end}}">审核中</a>
|
||
<a href="/studio/posts?status=draft" class="status-tab {{if eq .CurrentStatus "draft"}}active{{end}}">草稿</a>
|
||
<a href="/studio/posts?status=rejected" class="status-tab {{if eq .CurrentStatus "rejected"}}active{{end}}">已退回</a>
|
||
</div>
|
||
|
||
{{if .Posts}}
|
||
<div class="post-list">
|
||
{{range .Posts}}
|
||
<div class="post-item">
|
||
<div class="post-item-main">
|
||
<a href="/posts/{{.ID}}" class="post-item-title" target="_blank">{{.Title}}</a>
|
||
<div class="post-item-meta">
|
||
<span class="post-status-badge status-{{.Status}}">{{index $.StatusNames .Status}}</span>
|
||
{{if .IsLocked}}<span class="post-status-badge status-locked">已锁定</span>{{end}}
|
||
<span>{{.CreatedAt.Format "2006-01-02 15:04"}}</span>
|
||
{{if .RejectReason}}
|
||
<span class="post-reject-hint">退回理由:{{.RejectReason}}</span>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
<div class="post-item-actions">
|
||
{{if not .IsLocked}}<a href="/studio/write?id={{.ID}}" class="action-btn">编辑</a>{{end}}
|
||
<a href="/posts/{{.ID}}" target="_blank" class="action-btn">查看</a>
|
||
<button class="action-btn danger" data-post-id="{{.ID}}" data-action="delete" title="删除">删除</button>
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
<!-- 分页 -->
|
||
{{if gt .TotalPages 1}}
|
||
<div class="pagination">
|
||
{{if gt .Page 1}}
|
||
<a href="/studio/posts?status={{$.CurrentStatus}}&page={{subtract .Page 1}}" class="page-btn">上一页</a>
|
||
{{end}}
|
||
<span class="page-info">第 {{.Page}} / {{.TotalPages}} 页(共 {{.Total}} 篇)</span>
|
||
{{if lt .Page .TotalPages}}
|
||
<a href="/studio/posts?status={{$.CurrentStatus}}&page={{add .Page 1}}" class="page-btn">下一页</a>
|
||
{{end}}
|
||
</div>
|
||
{{end}}
|
||
|
||
{{else}}
|
||
<div class="studio-empty">
|
||
<p>还没有{{if .CurrentStatus}}{{index $.StatusNames .CurrentStatus}}{{end}}内容的文章</p>
|
||
<a href="/studio/write" class="btn-primary">去写一篇</a>
|
||
</div>
|
||
{{end}}
|
||
{{end}}
|
||
</main>
|
||
</div>
|
||
|
||
<script nonce="{{.CSPNonce}}">
|
||
function deletePost(id) {
|
||
showConfirm('确认', '确定要删除这篇文章吗?').then(function(ok) {
|
||
if (!ok) return;
|
||
fetch('/api/studio/posts/' + id, {
|
||
method: 'DELETE',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-CSRF-Token': getCSRFToken()
|
||
}
|
||
})
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
location.reload();
|
||
} else {
|
||
alert(data.message || '删除失败');
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// 事件委托代替内联 onclick(满足 CSP 无 unsafe-inline)
|
||
document.addEventListener('click', function(e) {
|
||
var btn = e.target.closest('[data-action="delete"]');
|
||
if (btn) {
|
||
deletePost(btn.getAttribute('data-post-id'));
|
||
}
|
||
});
|
||
</script>
|
||
|
||
{{template "layout/footer.html" .}}
|
||
|
||
</body>
|
||
</html>
|