feat(stats): 新增公开数据页 /stats,入口收敛到页脚
首页底部那张「站点统计」卡片下线,完整数据移到公开只读页 /stats: 今日实时数、概览六格、近 30 天折线与 12 个月柱状、三个占比环、 7×24 时段热力图、提问字数与回答耗时分布。 - 聚合在 internal/db/analytics.go(SUM(CASE WHEN),方言差异收敛在 analyticsDialectFor) - 结果按自然日缓存,跨日重算一次后全站共用;重算失败降级返回上一份快照 - 图表零前端依赖:服务端算坐标的 SVG + CSS grid,禁用 JS 页面仍完整 - 环比取「上月 vs 上上月」:本月未过完,否则每月 1 号会得出 -95% - 入口只在页脚「社区规则」与「找站长」之间;route.Home 不再计算统计 - 补 questions(created_at) 索引;启动后异步预热当天快照 - 测试:analytics 连真库验证软删除不计入、分桶下标、DOW 对齐
This commit is contained in:
@@ -951,4 +951,81 @@ var enDict = map[string]string{
|
||||
"theme.name.sakura": "Sakura",
|
||||
"theme.name.shiroko": "Shiroko",
|
||||
"theme.name.new-sakura": "New Sakura",
|
||||
|
||||
// Site statistics page (/stats): aggregate numbers only
|
||||
"site.footer.stats": "Stats",
|
||||
"stats.title": "Site statistics",
|
||||
"stats.lead": "Only aggregate numbers here: how many questions the site receives, how fast they get answered, and when people tend to show up. No individual question, asker identity, or source address is shown.",
|
||||
"stats.unavailable": "Statistics are temporarily unavailable. Please check back later.",
|
||||
|
||||
"stats.today.questions": "Asked today",
|
||||
"stats.today.answers": "Answered today",
|
||||
"stats.today.tag": "(live)",
|
||||
|
||||
"stats.kpi.users": "Registered users",
|
||||
"stats.kpi.questions": "Questions asked",
|
||||
"stats.kpi.answered": "Answered",
|
||||
"stats.kpi.answerRate": "Answer rate",
|
||||
"stats.kpi.activeBoxes": "Boxes that received questions",
|
||||
"stats.kpi.messages": "Direct messages",
|
||||
|
||||
"stats.insight.title": "At a glance",
|
||||
"stats.insight.note": "Each line below is read straight from the numbers above — no guesswork.",
|
||||
"stats.insight.empty": "Not enough question data yet.",
|
||||
"stats.insight.daily30": "%s questions in the last 30 days, about %.1f per day.",
|
||||
"stats.insight.peak": "Busiest day was %s with %s questions.",
|
||||
"stats.insight.busiest": "Questions cluster around %s %d:00.",
|
||||
"stats.insight.mom": "Last month versus the month before: %s%% questions.",
|
||||
"stats.insight.fastReply": "%s%% of answered questions got a reply within 24 hours.",
|
||||
"stats.insight.private": "%s%% of questions were sent privately.",
|
||||
|
||||
"stats.trend.dailyTitle": "Questions over the last 30 days",
|
||||
"stats.trend.dailyNote": "Daily question count.",
|
||||
"stats.trend.monthlyTitle": "Questions per month (last 12)",
|
||||
"stats.trend.monthlyNote": "The last bar is the current month, still in progress.",
|
||||
|
||||
"stats.mix.title": "Composition",
|
||||
"stats.mix.note": "Three ratios: public or private, answered or not, and whether the asker was signed in.",
|
||||
"stats.mix.public": "Public questions",
|
||||
"stats.mix.answered": "Answered",
|
||||
"stats.mix.login": "From signed-in users",
|
||||
|
||||
"stats.heat.title": "When questions arrive",
|
||||
"stats.heat.note": "Questions from the last %d days grouped by weekday and hour — darker means busier.",
|
||||
"stats.heat.less": "Less",
|
||||
"stats.heat.more": "More",
|
||||
|
||||
"stats.content.title": "Length and pace",
|
||||
"stats.content.note": "How long questions are, and how fast they get answered.",
|
||||
"stats.content.lengthTitle": "Question length",
|
||||
"stats.content.replyTitle": "Time to answer",
|
||||
|
||||
"stats.len.1": "under 20 chars",
|
||||
"stats.len.2": "20–49 chars",
|
||||
"stats.len.3": "50–99 chars",
|
||||
"stats.len.4": "100–199 chars",
|
||||
"stats.len.5": "200–499 chars",
|
||||
"stats.len.6": "500+ chars",
|
||||
|
||||
"stats.reply.1": "within 1 hour",
|
||||
"stats.reply.2": "1–6 hours",
|
||||
"stats.reply.3": "6–24 hours",
|
||||
"stats.reply.4": "1–3 days",
|
||||
"stats.reply.5": "3–7 days",
|
||||
"stats.reply.6": "over 7 days",
|
||||
|
||||
"stats.wd.1": "Mon",
|
||||
"stats.wd.2": "Tue",
|
||||
"stats.wd.3": "Wed",
|
||||
"stats.wd.4": "Thu",
|
||||
"stats.wd.5": "Fri",
|
||||
"stats.wd.6": "Sat",
|
||||
"stats.wd.7": "Sun",
|
||||
|
||||
"stats.foot.dataDate": "Data as of",
|
||||
"stats.foot.updated": "computed at",
|
||||
"stats.foot.prevMonth": "Last question:",
|
||||
"stats.foot.prevAnswer": "Last answer:",
|
||||
"stats.foot.privacy": "All figures are aggregates; no individual question, asker, or source address is shown.",
|
||||
"stats.foot.cacheNote": "Totals and charts are a snapshot taken at 00:00 local time, refreshed once a day; the two \"today\" figures are live.",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user