feat: SSR 问答帖发帖与解决状态切换

compose 支持 question;详情徽章并由作者/管理员切换。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-30 02:04:56 +08:00
parent 92b68b9eef
commit 303755b47a
9 changed files with 71 additions and 11 deletions

View File

@@ -67,7 +67,7 @@ func (d Deps) ComposePost(c *gin.Context) {
form := composeFormFrom(c)
htmlBody := services.ComposeBodyToHTML(form.Content)
postType := form.PostType
if postType != models.PostTypePoll {
if postType != models.PostTypePoll && postType != models.PostTypeQuestion {
postType = models.PostTypeNormal
}
post, err := d.Post.Create(ctx.UserID(), form.BoardID, form.Title, htmlBody, form.Tags, postType, ctx.SkipsModeration())
@@ -197,7 +197,7 @@ func composeFormFrom(c *gin.Context) composeForm {
maxChoices = 1
}
postType := strings.TrimSpace(c.PostForm("post_type"))
if postType != models.PostTypePoll {
if postType != models.PostTypePoll && postType != models.PostTypeQuestion {
postType = models.PostTypeNormal
}
return composeForm{

View File

@@ -33,6 +33,7 @@ func Register(r *gin.Engine, deps Deps, authMW *auth.AuthMiddleware) {
g.POST("/post/:id/favorite", authMW.RequireAuth(), deps.PostFavorite)
g.POST("/post/:id/poll/vote", authMW.RequireAuth(), deps.PostPollVote)
g.POST("/post/:id/poll/close", authMW.RequireAuth(), deps.PostPollClose)
g.POST("/post/:id/question/resolve", authMW.RequireAuth(), deps.PostQuestionResolvePost)
g.POST("/post/:id/unlock", authMW.RequireAuth(), deps.PostUnlock)
g.POST("/post/:id/report", authMW.RequireAuth(), deps.PostReportPost)
g.POST("/post/:id/comments/:cid/report", authMW.RequireAuth(), deps.CommentReportPost)

View File

@@ -46,7 +46,10 @@ type PostPageData struct {
Status string
StatusLabel string
ShowModerationBanner bool
Poll *postPollView
IsQuestion bool
QuestionResolved bool
CanToggleQuestion bool
Poll *postPollView
}
type postPollOptionView struct {
@@ -199,7 +202,10 @@ func (d Deps) PostView(c *gin.Context) {
Status: post.Status,
StatusLabel: statusLabel,
ShowModerationBanner: showBanner,
Poll: pollView,
IsQuestion: post.PostType == models.PostTypeQuestion,
QuestionResolved: post.QuestionResolved,
CanToggleQuestion: post.PostType == models.PostTypeQuestion && (ctx.IsAdmin() || post.UserID == ctx.UserID()),
Poll: pollView,
})
}
@@ -468,6 +474,33 @@ func (d Deps) PostPollClose(c *gin.Context) {
ctx.Redirect(fmt.Sprintf("/post/%d", id))
}
// PostQuestionResolvePost 标记问答帖已解决 / 未解决
func (d Deps) PostQuestionResolvePost(c *gin.Context) {
ctx := d.ctx(c)
id, err := parsePostID(c, d)
if err != nil || id == 0 {
d.render404(ctx)
return
}
if !ctx.CheckCSRF() {
ctx.SetFlash("无效请求,请重试")
ctx.Redirect(fmt.Sprintf("/post/%d", id))
return
}
resolved := c.PostForm("resolved") == "1" || c.PostForm("resolved") == "on"
if err := d.Post.SetQuestionResolved(ctx.UserID(), id, ctx.IsAdmin(), resolved); err != nil {
ctx.SetFlash(err.Error())
ctx.Redirect(fmt.Sprintf("/post/%d", id))
return
}
if resolved {
ctx.SetFlash("已标为已解决")
} else {
ctx.SetFlash("已标为未解决")
}
ctx.Redirect(fmt.Sprintf("/post/%d", id))
}
type commentEditData struct {
PageChrome
PostID uint