- 替换全部 11 个文件中 36 处 alert() 为 showToast() - API 错误/异常使用 showToast(msg, 'error'),3秒自动消失 - 表单校验提示使用 showToast(msg, 'warning'),3秒自动消失 - 成功确认使用 showToast(msg, 'success'),3秒自动消失 - 移除 post-energize.js 中与全局 showToast 冲突的本地实现 - 删除 posts.css 中已失去引用的 .energize-toast 样式 - 保留 showConfirm() 自定义确认弹窗(需用户确认的操作)
121 lines
3.8 KiB
HTML
121 lines
3.8 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>
|
||
<span class="studio-subtitle">共 {{.Total}} 篇草稿</span>
|
||
</div>
|
||
|
||
{{if .Error}}
|
||
<div class="studio-error">{{.Error}}</div>
|
||
{{else}}
|
||
{{if .Posts}}
|
||
<div class="post-list">
|
||
{{range .Posts}}
|
||
<div class="post-item">
|
||
<div class="post-item-main">
|
||
<span class="post-item-title draft-title">{{if .Title}}{{.Title}}{{else}}无标题{{end}}</span>
|
||
<div class="post-item-meta">
|
||
<span class="post-status-badge status-draft">草稿</span>
|
||
<span>{{.CreatedAt.Format "2006-01-02 15:04"}}</span>
|
||
</div>
|
||
</div>
|
||
<div class="post-item-actions">
|
||
<a href="/studio/write?id={{.ID}}" class="action-btn primary">继续编辑</a>
|
||
<button class="action-btn" data-post-id="{{.ID}}" data-action="submit" title="提交发布">提交</button>
|
||
<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/drafts?page={{subtract .Page 1}}" class="page-btn">上一页</a>
|
||
{{end}}
|
||
<span class="page-info">第 {{.Page}} / {{.TotalPages}} 页</span>
|
||
{{if lt .Page .TotalPages}}
|
||
<a href="/studio/drafts?page={{add .Page 1}}" class="page-btn">下一页</a>
|
||
{{end}}
|
||
</div>
|
||
{{end}}
|
||
|
||
{{else}}
|
||
<div class="studio-empty">
|
||
<p>✨ 草稿箱是空的</p>
|
||
<a href="/studio/write" class="btn-primary">开始写作</a>
|
||
</div>
|
||
{{end}}
|
||
{{end}}
|
||
</main>
|
||
</div>
|
||
|
||
<script nonce="{{.CSPNonce}}">
|
||
function submitPost(id) {
|
||
showConfirm('确认', '确定要提交这篇草稿进行审核吗?').then(function(ok) {
|
||
if (!ok) return;
|
||
fetch('/api/studio/posts/' + id + '/submit', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'X-CSRF-Token': getCSRFToken()
|
||
}
|
||
})
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
location.reload();
|
||
} else {
|
||
showToast(data.message || '提交失败', 'error');
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
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 {
|
||
showToast(data.message || '删除失败', 'error');
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// 事件委托代替内联 onclick(满足 CSP 无 unsafe-inline)
|
||
document.addEventListener('click', function(e) {
|
||
var btn = e.target.closest('[data-action]');
|
||
if (!btn) return;
|
||
var id = btn.getAttribute('data-post-id');
|
||
var action = btn.getAttribute('data-action');
|
||
if (action === 'delete') {
|
||
deletePost(id);
|
||
} else if (action === 'submit') {
|
||
submitPost(id);
|
||
}
|
||
});
|
||
</script>
|
||
|
||
{{template "layout/footer.html" .}}
|
||
|
||
</body>
|
||
</html>
|