feat: 已发布帖子编辑后进修订审核,通过前保持展示旧内容

- Post 模型新增 PendingTitle/PendingBody 字段,分离已发布内容与待审修订
- Update: approved 帖子编辑写入 Pending 字段,不覆盖正文,不改变发布状态
- Approve: 有 PendingBody 时复制到正式字段后清空,无 PendingBody 走首次审核
- Reject: 有 PendingBody 时仅清空待审修订(保持已发布),无 PendingBody 走普通退回
- 新增 ListPendingRevisions 查询,管理后台独立展示"修订待审核"区域
- 详情页展示"修订审核中"标识,编辑页加载待审内容
- 通过修订后直接覆盖,不保留历史版本
This commit is contained in:
2026-05-30 20:24:43 +08:00
parent 89fa50a013
commit eabc1e7d3d
11 changed files with 124 additions and 9 deletions

View File

@ -22,6 +22,47 @@
<div class="error-message">{{.Error}}</div>
{{end}}
{{if .Revisions}}
<div class="revision-section">
<h2>修订待审核 <span class="revision-count">{{len .Revisions}}</span></h2>
<table class="admin-table revision-table">
<thead>
<tr>
<th>ID</th>
<th>标题</th>
<th>作者</th>
<th>状态</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{range .Revisions}}
<tr class="post-row revision-row">
<td>{{.ID}}</td>
<td><a href="/posts/{{.ID}}" target="_blank" class="post-link">{{.Title}}</a> <span class="revision-badge">修订中</span></td>
<td>{{if .AuthorName}}{{.AuthorName}}({{.UserID}}){{else}}UID{{.UserID}}{{end}}</td>
<td><span class="status-badge status-{{.Status}}">{{index $.StatusNames .Status}}</span>{{if .IsLocked}} <span class="status-badge status-locked">已锁定</span>{{end}}</td>
<td>{{.CreatedAt.Format "2006-01-02 15:04"}}</td>
<td class="actions-cell">
<div class="action-btns">
<button class="btn btn-sm btn-success post-approve" data-id="{{.ID}}">通过修订</button>
<button class="btn btn-sm btn-warning post-reject" data-id="{{.ID}}">退回修订</button>
{{if and (not .IsLocked)}}
<button class="btn btn-sm btn-danger post-lock" data-id="{{.ID}}">锁定</button>
{{end}}
{{if .IsLocked}}
<button class="btn btn-sm btn-success post-unlock" data-id="{{.ID}}">解锁</button>
{{end}}
</div>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{end}}
<table class="admin-table">
<thead>
<tr>
@ -34,13 +75,13 @@
</tr>
</thead>
<tbody>
{{if eq (len .Posts) 0}}
{{if and (eq (len .Posts) 0) (eq (len .Revisions) 0)}}
<tr><td colspan="6" class="empty">暂无帖子</td></tr>
{{end}}
{{range .Posts}}
<tr class="post-row">
<td>{{.ID}}</td>
<td><a href="/posts/{{.ID}}" target="_blank" class="post-link">{{.Title}}</a></td>
<td><a href="/posts/{{.ID}}" target="_blank" class="post-link">{{.Title}}</a>{{if .PendingBody}} <span class="revision-badge">修订中</span>{{end}}</td>
<td>{{if .AuthorName}}{{.AuthorName}}({{.UserID}}){{else}}UID{{.UserID}}{{end}}</td>
<td><span class="status-badge status-{{.Status}}">{{index $.StatusNames .Status}}</span>{{if .IsLocked}} <span class="status-badge status-locked">已锁定</span>{{end}}</td>
<td>{{.CreatedAt.Format "2006-01-02 15:04"}}</td>
@ -50,9 +91,13 @@
<button class="btn btn-sm btn-success post-approve" data-id="{{.ID}}">通过</button>
<button class="btn btn-sm btn-warning post-reject" data-id="{{.ID}}">退回</button>
{{end}}
{{if eq .Status "approved"}}
{{if and (eq .Status "approved") (not .PendingBody)}}
<button class="btn btn-sm btn-warning post-reject" data-id="{{.ID}}">退回</button>
{{end}}
{{if and (eq .Status "approved") .PendingBody}}
<button class="btn btn-sm btn-success post-approve" data-id="{{.ID}}">通过修订</button>
<button class="btn btn-sm btn-warning post-reject" data-id="{{.ID}}">退回修订</button>
{{end}}
{{if and (not .IsLocked) (ne .Status "pending")}}
<button class="btn btn-sm btn-danger post-lock" data-id="{{.ID}}">锁定</button>
{{end}}

View File

@ -81,6 +81,13 @@
.status-rejected { background: #fee2e2; color: #dc2626; }
.status-locked { background: #fee2e2; color: #b91c1c; }
.revision-section { margin-bottom: 24px; }
.revision-section h2 { font-size: 16px; font-weight: 600; margin-bottom: 12px; color: #4338ca; }
.revision-count { background: #4338ca; color: #fff; border-radius: 10px; padding: 1px 8px; font-size: 13px; }
.revision-table { border: 2px solid #c7d2fe; }
.revision-row { background: #eef2ff; }
.revision-badge { background: #e0e7ff; color: #4338ca; font-size: 11px; border-radius: 4px; padding: 1px 6px; margin-left: 6px; }
.actions-cell { min-width: 180px; }
.action-btns {