fix templates v1

This commit is contained in:
tamakyi
2026-10-22 17:04:10 +08:00
parent 8fcb23f7b1
commit bd02eb7ed2
12 changed files with 293 additions and 12 deletions
+85 -9
View File
@@ -73,6 +73,16 @@ func Questioner(ctx context.Context, pageUser *db.User) {
ctx.Map(canDelete)
ctx.Data["CanDelete"] = canDelete
// 箱主导航:下一条未读。只查一条(不做 count),用于决定详情页是否渲染该按钮。
if canDelete {
nextUnread, err := db.Questions.NextUnread(ctx.Request().Context(), pageUser.ID, question.ID)
if err != nil {
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to get next unread question")
} else if nextUnread != nil {
ctx.Data["NextUnreadID"] = nextUnread.ID
}
}
// ---------- 追问 ----------
followUps, err := db.FollowUps.GetByQuestionID(ctx.Request().Context(), questionID)
if err != nil {
@@ -116,18 +126,14 @@ func Questioner(ctx context.Context, pageUser *db.User) {
ctx.Data["BackFrom"] = backFrom
// 从后台返回时,把进入时携带的筛选参数(sort/status/type/read/q)原样回传,
// 使"返回"跳回带筛选条件的后台列表,避免丢失已选的筛选/搜索条件。
if backFrom == "admin" {
backQuery := url.Values{}
for _, key := range []string{"sort", "status", "type", "read", "q"} {
if v := ctx.Query(key); v != "" {
backQuery.Set(key, v)
}
}
// 「下一条未读」同样带上这份参数,否则答完一条后"返回"就掉回箱主页了。
if backQuery := adminBackQuery(ctx); backFrom == "admin" {
backTo := "/user/questions"
if qs := backQuery.Encode(); qs != "" {
backTo += "?" + qs
if backQuery != "" {
backTo += "?" + backQuery
}
ctx.Data["BackTo"] = backTo
ctx.Data["NextQuery"] = backQuery
}
ctx.Map(question)
@@ -258,6 +264,18 @@ func PublishAnswer(ctx context.Context, pageUser *db.User, question *db.Question
} else {
ctx.SetSuccessFlash(i18n.T(ctx.Lang(), "question.flash.answered"))
}
// 「回答并下一条」:同一表单的第二个提交按钮带 next=1。答题后本条已锁定为已读,
// 直接打开最早的一条未读;队列已空(渲染后被打空的竞态)则退回当前页。
if ctx.Request().FormValue("next") == "1" {
nextUnread, err := db.Questions.NextUnread(ctx.Request().Context(), pageUser.ID, question.ID)
if err != nil {
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to get next unread question")
} else if nextUnread != nil {
ctx.Redirect(questionPath(ctx, pageUser.Domain, nextUnread.ID))
return
}
}
ctx.Redirect(fmt.Sprintf("/_/%s/%d", pageUser.Domain, question.ID))
}
@@ -396,3 +414,61 @@ func SetUnread(ctx context.Context, pageUser *db.User, question *db.Question, ca
ctx.SetSuccessFlash(i18n.T(ctx.Lang(), "question.flash.markedUnread"))
ctx.Redirect(fmt.Sprintf("/user/questions#question-%d", question.ID))
}
// NextUnread 阅后即走:把当前提问标记为已读,然后打开最早的一条未读提问。
//
// 必须同时改状态:只跳转而不标记的话,当前这条仍是未读,下一次取「最早未读」
// 又会把它选回来,两条未读之间会来回打转。
func NextUnread(ctx context.Context, pageUser *db.User, question *db.Question, canDelete bool) {
if !canDelete {
ctx.Redirect("/_/" + pageUser.Domain)
return
}
if err := db.Questions.SetRead(ctx.Request().Context(), question.ID); err != nil {
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to set question read")
ctx.SetInternalError()
ctx.Success("question/item")
return
}
nextUnread, err := db.Questions.NextUnread(ctx.Request().Context(), pageUser.ID, question.ID)
if err != nil {
logrus.WithContext(ctx.Request().Context()).WithError(err).Error("Failed to get next unread question")
ctx.SetInternalError()
ctx.Success("question/item")
return
}
if nextUnread == nil {
ctx.SetSuccessFlash(i18n.T(ctx.Lang(), "question.flash.noUnread"))
ctx.Redirect(questionPath(ctx, pageUser.Domain, question.ID))
return
}
ctx.Redirect(questionPath(ctx, pageUser.Domain, nextUnread.ID))
}
// questionPath 拼单题页地址;从后台进入时带上筛选参数,跳转后「返回」仍回原列表。
func questionPath(ctx context.Context, domain string, questionID uint) string {
path := fmt.Sprintf("/_/%s/%d", domain, questionID)
if backQuery := adminBackQuery(ctx); backQuery != "" {
path += "?" + backQuery
}
return path
}
// adminBackQuery 提取后台列表的筛选参数(仅 from=admin 时有效),供单题页的
// 「返回」「下一条未读」沿用。POST 请求从表单 action 的 query 里读取。
func adminBackQuery(ctx context.Context) string {
if ctx.Query("from") != "admin" {
return ""
}
backQuery := url.Values{}
for _, key := range []string{"sort", "status", "type", "read", "q"} {
if v := ctx.Query(key); v != "" {
backQuery.Set(key, v)
}
}
return backQuery.Encode()
}