feat: 帖/评待审与被拒状态对作者可见
详情页横幅与楼层标签,避免作者误以为内容未保存。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -63,7 +63,7 @@
|
|||||||
- [x] 点赞切换;收藏切换;收藏列表 — SSR `/favorites`
|
- [x] 点赞切换;收藏切换;收藏列表 — SSR `/favorites`
|
||||||
- [x] 浏览量 — 详情页计数
|
- [x] 浏览量 — 详情页计数
|
||||||
- [x] 举报帖子 — SSR 表单 + `/admin/reports`
|
- [x] 举报帖子 — SSR 表单 + `/admin/reports`
|
||||||
- [ ] 内容审核状态展示(作者可见待审/被拒)
|
- [x] 内容审核状态展示(作者可见待审/被拒)— SSR 帖详情横幅 + 评论楼层标签
|
||||||
|
|
||||||
### D.1 帖子类型
|
### D.1 帖子类型
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
- [x] 评论举报 — SSR
|
- [x] 评论举报 — SSR
|
||||||
- [x] @ 提及 → 通知 — SSR 发评/审通调用 `NotifyCommentMentions`
|
- [x] @ 提及 → 通知 — SSR 发评/审通调用 `NotifyCommentMentions`
|
||||||
- [x] 回复提醒(站内信 + 可选邮件)— SSR 发评/审通调用 `NotifyCommentPublished`
|
- [x] 回复提醒(站内信 + 可选邮件)— SSR 发评/审通调用 `NotifyCommentPublished`
|
||||||
- [ ] 审核中 / 被拒评论可见性规则
|
- [x] 审核中 / 被拒评论可见性规则 — 服务层已有;SSR 楼层标签(作者/管理员)
|
||||||
- [x] 管理员:通过 / 拒绝待审评论 — SSR `/admin/moderation`(回收站/修订未迁)
|
- [x] 管理员:通过 / 拒绝待审评论 — SSR `/admin/moderation`(回收站/修订未迁)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -85,7 +85,7 @@
|
|||||||
|
|
||||||
**Feed**:排序条(最新发帖 / 最新回复 / 热门)+ 搜索面板(关键词、标签、作者、仅标题;已迁 SSR GET)+ 列表项(标题、作者、板块徽章、回复数、置顶/精华)。虚拟滚动 / `feed_list_style` 未迁。
|
**Feed**:排序条(最新发帖 / 最新回复 / 热门)+ 搜索面板(关键词、标签、作者、仅标题;已迁 SSR GET)+ 列表项(标题、作者、板块徽章、回复数、置顶/精华)。虚拟滚动 / `feed_list_style` 未迁。
|
||||||
|
|
||||||
**帖子详情**:标题区操作(赞、藏、举报、编辑、管理操作)→ 特殊组件(投票卡 / 悬赏条 / 抽奖卡)→ 正文 `PostContent`(门控块 UI)→ 文章目录 → 作者卡片 → 修订入口 → 评论线程 + 评论框。
|
**帖子详情**:标题区操作(赞、藏、举报、编辑、管理操作)→ 待审/被拒横幅(作者/管理员)→ 特殊组件(投票卡 / 悬赏条 / 抽奖卡)→ 正文 `PostContent`(门控块 UI)→ 文章目录 → 作者卡片 → 修订入口 → 评论线程 + 评论框。
|
||||||
|
|
||||||
### 2.3 右栏 RightPanel
|
### 2.3 右栏 RightPanel
|
||||||
|
|
||||||
|
|||||||
@@ -298,6 +298,25 @@ body.j13-body {
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
.j13-tag--pin { background: #fef3c7; color: #92400e; }
|
.j13-tag--pin { background: #fef3c7; color: #92400e; }
|
||||||
|
.j13-tag--pending { background: #fff7ed; color: #9a3412; }
|
||||||
|
.j13-tag--rejected { background: #fef2f2; color: #991b1b; }
|
||||||
|
.j13-mod-banner {
|
||||||
|
margin: 0.5rem 0 0.75rem;
|
||||||
|
padding: 0.65rem 0.85rem;
|
||||||
|
border-radius: var(--j13-radius);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.j13-mod-banner--pending {
|
||||||
|
background: #fff7ed;
|
||||||
|
color: #9a3412;
|
||||||
|
border: 1px solid #fed7aa;
|
||||||
|
}
|
||||||
|
.j13-mod-banner--rejected {
|
||||||
|
background: #fef2f2;
|
||||||
|
color: #991b1b;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
}
|
||||||
.j13-tag--feat { background: #ede9fe; color: #5b21b6; }
|
.j13-tag--feat { background: #ede9fe; color: #5b21b6; }
|
||||||
|
|
||||||
.j13-empty { color: var(--j13-muted); }
|
.j13-empty { color: var(--j13-muted); }
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ type PostPageData struct {
|
|||||||
CanViewRevisions bool
|
CanViewRevisions bool
|
||||||
CanReportPost bool
|
CanReportPost bool
|
||||||
IsAdmin bool
|
IsAdmin bool
|
||||||
|
Status string
|
||||||
|
StatusLabel string
|
||||||
|
ShowModerationBanner bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommentView 评论
|
// CommentView 评论
|
||||||
@@ -63,6 +66,8 @@ type CommentView struct {
|
|||||||
CanReport bool
|
CanReport bool
|
||||||
CanEdit bool
|
CanEdit bool
|
||||||
CanDelete bool
|
CanDelete bool
|
||||||
|
Status string
|
||||||
|
StatusLabel string
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostView GET /post/:id
|
// PostView GET /post/:id
|
||||||
@@ -101,6 +106,12 @@ func (d Deps) PostView(c *gin.Context) {
|
|||||||
CanReport: ctx.IsSigned() && (cm.UserID == 0 || cm.UserID != ctx.UserID()),
|
CanReport: ctx.IsSigned() && (cm.UserID == 0 || cm.UserID != ctx.UserID()),
|
||||||
CanEdit: !cm.ContentHidden && d.Comment.CanUserEditComment(&cm, ctx.UserID(), ctx.IsAdmin()),
|
CanEdit: !cm.ContentHidden && d.Comment.CanUserEditComment(&cm, ctx.UserID(), ctx.IsAdmin()),
|
||||||
CanDelete: !cm.ContentHidden && d.Comment.CanUserDeleteComment(&cm, ctx.UserID(), ctx.IsAdmin()),
|
CanDelete: !cm.ContentHidden && d.Comment.CanUserDeleteComment(&cm, ctx.UserID(), ctx.IsAdmin()),
|
||||||
|
Status: cm.Status,
|
||||||
|
}
|
||||||
|
if cm.Status == models.ContentStatusPending || cm.Status == models.ContentStatusRejected {
|
||||||
|
if ctx.IsAdmin() || (cm.UserID > 0 && cm.UserID == ctx.UserID()) {
|
||||||
|
view.StatusLabel = contentStatusLabel(cm.Status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cm.ReplyTarget != nil {
|
if cm.ReplyTarget != nil {
|
||||||
view.ReplyToID = cm.ReplyTarget.ID
|
view.ReplyToID = cm.ReplyTarget.ID
|
||||||
@@ -131,6 +142,15 @@ func (d Deps) PostView(c *gin.Context) {
|
|||||||
chrome := d.chrome(ctx, post.Title+" · "+d.Settings.SiteBranding().Name, "", "post/body")
|
chrome := d.chrome(ctx, post.Title+" · "+d.Settings.SiteBranding().Name, "", "post/body")
|
||||||
chrome.ActiveBoard = post.BoardID
|
chrome.ActiveBoard = post.BoardID
|
||||||
|
|
||||||
|
statusLabel := ""
|
||||||
|
showBanner := false
|
||||||
|
if post.Status == models.ContentStatusPending || post.Status == models.ContentStatusRejected {
|
||||||
|
if ctx.IsAdmin() || post.UserID == ctx.UserID() {
|
||||||
|
statusLabel = contentStatusLabel(post.Status)
|
||||||
|
showBanner = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, "post", PostPageData{
|
ctx.HTML(http.StatusOK, "post", PostPageData{
|
||||||
PageChrome: chrome, PostID: post.ID,
|
PageChrome: chrome, PostID: post.ID,
|
||||||
PostPath: url.QueryEscape(fmt.Sprintf("/post/%d", post.ID)),
|
PostPath: url.QueryEscape(fmt.Sprintf("/post/%d", post.ID)),
|
||||||
@@ -147,9 +167,23 @@ func (d Deps) PostView(c *gin.Context) {
|
|||||||
CanViewRevisions: canViewPostRevisions(post, ctx.UserID(), ctx.IsAdmin()),
|
CanViewRevisions: canViewPostRevisions(post, ctx.UserID(), ctx.IsAdmin()),
|
||||||
CanReportPost: ctx.IsSigned() && post.UserID != ctx.UserID(),
|
CanReportPost: ctx.IsSigned() && post.UserID != ctx.UserID(),
|
||||||
IsAdmin: ctx.IsAdmin(),
|
IsAdmin: ctx.IsAdmin(),
|
||||||
|
Status: post.Status,
|
||||||
|
StatusLabel: statusLabel,
|
||||||
|
ShowModerationBanner: showBanner,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func contentStatusLabel(status string) string {
|
||||||
|
switch status {
|
||||||
|
case models.ContentStatusPending:
|
||||||
|
return "审核中"
|
||||||
|
case models.ContentStatusRejected:
|
||||||
|
return "已拒绝"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func postTypeLabel(t string) string {
|
func postTypeLabel(t string) string {
|
||||||
switch t {
|
switch t {
|
||||||
case models.PostTypeQuestion:
|
case models.PostTypeQuestion:
|
||||||
|
|||||||
@@ -2,7 +2,13 @@
|
|||||||
<article class="j13-post" data-post-id="{{.PostID}}" data-csrf="{{.CSRF}}" data-logged-in="{{if .LoggedIn}}1{{else}}0{{end}}">
|
<article class="j13-post" data-post-id="{{.PostID}}" data-csrf="{{.CSRF}}" data-logged-in="{{if .LoggedIn}}1{{else}}0{{end}}">
|
||||||
<header class="j13-post__header">
|
<header class="j13-post__header">
|
||||||
<h1 class="j13-post__title">{{.PostTitle}}</h1>
|
<h1 class="j13-post__title">{{.PostTitle}}</h1>
|
||||||
|
{{if .ShowModerationBanner}}
|
||||||
|
<p class="j13-mod-banner j13-mod-banner--{{.Status}}" role="status">
|
||||||
|
{{if eq .Status "pending"}}本帖正在审核中,仅你与管理员可见。{{else if eq .Status "rejected"}}本帖未通过审核,仅你与管理员可见。{{else}}{{.StatusLabel}}{{end}}
|
||||||
|
</p>
|
||||||
|
{{end}}
|
||||||
<div class="j13-post__meta">
|
<div class="j13-post__meta">
|
||||||
|
{{if .StatusLabel}}<span class="j13-tag j13-tag--{{.Status}}">{{.StatusLabel}}</span>{{end}}
|
||||||
{{if .Pinned}}<span class="j13-tag j13-tag--pin">置顶</span>{{end}}
|
{{if .Pinned}}<span class="j13-tag j13-tag--pin">置顶</span>{{end}}
|
||||||
{{if .Featured}}<span class="j13-tag j13-tag--feat">精华</span>{{end}}
|
{{if .Featured}}<span class="j13-tag j13-tag--feat">精华</span>{{end}}
|
||||||
{{if .EditLocked}}<span class="j13-tag">禁编</span>{{end}}
|
{{if .EditLocked}}<span class="j13-tag">禁编</span>{{end}}
|
||||||
@@ -98,6 +104,7 @@
|
|||||||
<span class="j13-comment__floor">#{{.Floor}}</span>
|
<span class="j13-comment__floor">#{{.Floor}}</span>
|
||||||
{{if .AuthorID}}<a href="/user/{{.AuthorID}}">{{.AuthorName}}</a>{{else}}<span>{{.AuthorName}}</span>{{end}}
|
{{if .AuthorID}}<a href="/user/{{.AuthorID}}">{{.AuthorName}}</a>{{else}}<span>{{.AuthorName}}</span>{{end}}
|
||||||
<span>{{.CreatedLabel}}</span>
|
<span>{{.CreatedLabel}}</span>
|
||||||
|
{{if .StatusLabel}}<span class="j13-tag j13-tag--{{.Status}}">{{.StatusLabel}}</span>{{end}}
|
||||||
{{if .IsPrivate}}<span class="j13-tag">私密</span>{{end}}
|
{{if .IsPrivate}}<span class="j13-tag">私密</span>{{end}}
|
||||||
{{if .ReplyToFloor}}
|
{{if .ReplyToFloor}}
|
||||||
<span class="j13-comment__reply-to">回复 <a href="#floor-{{.ReplyToFloor}}">#{{.ReplyToFloor}}</a>{{if .ReplyToAuthor}} {{.ReplyToAuthor}}{{end}}</span>
|
<span class="j13-comment__reply-to">回复 <a href="#floor-{{.ReplyToFloor}}">#{{.ReplyToFloor}}</a>{{if .ReplyToAuthor}} {{.ReplyToAuthor}}{{end}}</span>
|
||||||
|
|||||||
@@ -298,6 +298,25 @@ body.j13-body {
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
.j13-tag--pin { background: #fef3c7; color: #92400e; }
|
.j13-tag--pin { background: #fef3c7; color: #92400e; }
|
||||||
|
.j13-tag--pending { background: #fff7ed; color: #9a3412; }
|
||||||
|
.j13-tag--rejected { background: #fef2f2; color: #991b1b; }
|
||||||
|
.j13-mod-banner {
|
||||||
|
margin: 0.5rem 0 0.75rem;
|
||||||
|
padding: 0.65rem 0.85rem;
|
||||||
|
border-radius: var(--j13-radius);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
.j13-mod-banner--pending {
|
||||||
|
background: #fff7ed;
|
||||||
|
color: #9a3412;
|
||||||
|
border: 1px solid #fed7aa;
|
||||||
|
}
|
||||||
|
.j13-mod-banner--rejected {
|
||||||
|
background: #fef2f2;
|
||||||
|
color: #991b1b;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
}
|
||||||
.j13-tag--feat { background: #ede9fe; color: #5b21b6; }
|
.j13-tag--feat { background: #ede9fe; color: #5b21b6; }
|
||||||
|
|
||||||
.j13-empty { color: var(--j13-muted); }
|
.j13-empty { color: var(--j13-muted); }
|
||||||
|
|||||||
Reference in New Issue
Block a user