From c680671b7ef53d604ed9232064ae3207da5cb74f Mon Sep 17 00:00:00 2001 From: tamakyi Date: Fri, 23 Oct 2026 21:04:50 +0800 Subject: [PATCH] =?UTF-8?q?feat(user/questions):=20=E6=89=8B=E6=9C=BA?= =?UTF-8?q?=E7=AB=AF=E6=97=B6=E9=97=B4=E8=B7=A8=E5=B9=B4=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E8=A1=A5=E5=B9=B4=E4=BB=BD=EF=BC=8C=E9=81=BF=E5=85=8D=E7=9C=81?= =?UTF-8?q?=E7=95=A5=E5=B9=B4=E4=BB=BD=E5=90=8E=E4=BA=A7=E7=94=9F=E6=AD=A7?= =?UTF-8?q?=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DateCompact:与当前同一年的渲染「月-日 时:分」,跨年补回完整「年-月-日 时:分」。 只砍年份会让「去年今天」和「今年今天」显示成同一串,逐条补年份比按年分组便宜得多 (列表带游标分页 + 可切排序/筛选,组标题会跨页重复或错位)。 桌面端不受影响,仍显示 Y-m-d H:i:s。 测试覆盖年份边界(同年 1/1 与 12/31、跨年);预览数据里放了一条 2025 年的提问用于肉眼核对。 --- internal/template/date_compact_test.go | 30 ++++++++++++++++++++++++++ internal/template/template.go | 15 +++++++++++++ templates/user/question-list.html | 5 +++-- templates/zz_preview_test.go | 2 +- 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 internal/template/date_compact_test.go diff --git a/internal/template/date_compact_test.go b/internal/template/date_compact_test.go new file mode 100644 index 0000000..742b02b --- /dev/null +++ b/internal/template/date_compact_test.go @@ -0,0 +1,30 @@ +package template + +import ( + "testing" + "time" +) + +// dateCompact 是手机端列表的时间格式:同年省略年份,跨年补回年份。 +// 这条测试盯的是「年份边界」——同一年的 1 月 1 日也要省略年份, +// 不能因为「看起来像很久以前」就提前补年。 +func TestDateCompact(t *testing.T) { + now := time.Date(2026, 10, 23, 21, 0, 0, 0, time.Local) + + cases := []struct { + in time.Time + want string + }{ + {time.Date(2026, 9, 9, 1, 18, 3, 0, time.Local), "09-09 01:18"}, + {time.Date(2026, 1, 1, 0, 0, 0, 0, time.Local), "01-01 00:00"}, + {time.Date(2026, 12, 31, 23, 59, 59, 0, time.Local), "12-31 23:59"}, + {time.Date(2025, 9, 5, 4, 45, 22, 0, time.Local), "2025-09-05 04:45"}, + {time.Date(2027, 1, 1, 0, 0, 0, 0, time.Local), "2027-01-01 00:00"}, + } + + for _, c := range cases { + if got := dateCompact(c.in, now); got != c.want { + t.Errorf("dateCompact(%s) = %q, want %q", c.in.Format(time.RFC3339), got, c.want) + } + } +} diff --git a/internal/template/template.go b/internal/template/template.go index ec55fb3..71c0f30 100644 --- a/internal/template/template.go +++ b/internal/template/template.go @@ -47,6 +47,9 @@ func FuncMap() []template.FuncMap { format = replacer.Replace(format) return t.Format(format) }, + "DateCompact": func(t time.Time) string { + return dateCompact(t, time.Now()) + }, "QuestionFormat": func(input string) template.HTML { input = html.EscapeString(input) input = strings.ReplaceAll(input, "\n", "
") @@ -236,3 +239,15 @@ func FuncMap() []template.FuncMap { func Safe(raw string) template.HTML { return template.HTML(raw) } + +// dateCompact 手机端列表用的紧凑时间:与 now 同一年的只给「月-日 时:分」。 +// 手机一行的宽度放不下「Y-m-d H:i:s」(单它就要 127px),但只砍年份会让 +// 「去年的今天」和「今年今天」渲染成同一串,所以在跨年时自动补回年份。 +// 注意:这是「逐条补年份」,不是「按年分组」—— 列表带游标分页、可切排序与筛选, +// 分组标题会跨页重复/错位,收益不如补年份直接。 +func dateCompact(t, now time.Time) string { + if t.Year() == now.Year() { + return t.Format("01-02 15:04") + } + return t.Format("2006-01-02 15:04") +} diff --git a/templates/user/question-list.html b/templates/user/question-list.html index 8bea28b..f28621c 100644 --- a/templates/user/question-list.html +++ b/templates/user/question-list.html @@ -283,8 +283,9 @@
- {{Date .CreatedAt "m-d H:i"}}{{Date .CreatedAt "Y-m-d H:i:s"}} + 跨年的条目由 DateCompact 自动补回年份(否则「去年今天」和「今年今天」 + 会渲染成同一串)。tb-short / tb-text 与右侧状态标签共用 640px 断点。 --> + {{DateCompact .CreatedAt}}{{Date .CreatedAt "Y-m-d H:i:s"}} {{ if .IsPinned }} {{t $.LangCode "qlist.pinnedShort"}}{{t $.LangCode "qlist.pinned"}} {{ end }} diff --git a/templates/zz_preview_test.go b/templates/zz_preview_test.go index 89b02e0..ab3d636 100644 --- a/templates/zz_preview_test.go +++ b/templates/zz_preview_test.go @@ -304,7 +304,7 @@ func writeAdminListPreviews(t *testing.T, outDir string) { Link: "/_/test/1", IsAnswered: true, IsRead: true, QuestionID: 1, IsPinned: true, PinLink: "/_/test/1/pin"}, adminItem{Type: "question_private", CreatedAt: time.Now(), Content: "悄悄话:最近还好吗", Link: "/_/test/2", IsAnswered: false, IsPrivate: true, QuestionID: 2, PinLink: "/_/test/2/pin"}, - adminItem{Type: "question_public", CreatedAt: time.Now(), Content: "光环是什么材质的?", + adminItem{Type: "question_public", CreatedAt: time.Date(2025, 9, 5, 4, 45, 22, 0, time.Local), Content: "光环是什么材质的?", Link: "/_/test/3", IsAnswered: true, IsRead: false, QuestionID: 3, PinLink: "/_/test/3/pin"}, }, "ReceivedChats": []interface{}{