diff --git a/internal/web/static/css/app.css b/internal/web/static/css/app.css index 8210b29..a066039 100644 --- a/internal/web/static/css/app.css +++ b/internal/web/static/css/app.css @@ -1007,3 +1007,40 @@ label.f > span.span-actions { display: flex; align-items: center; justify-conten .filters-card.collapsed > .panel-fold { margin: 0; border-radius: var(--radius); } .filters-card.collapsed > :not(.panel-fold) { display: none; } } + +/* ---------- 窄屏:要横滑的宽表改成一屏一行的「字段 + 值」 ---------- + 地点库(8 列)、统计、专题、后台这几张表在手机上要横滑 300+px 才看得全,滑着还对不上表头。 + 窄屏改成每行一块、每格「字段名 + 值」竖排:不用横滑,也不用记「第几列是什么」。 + 字段名取 td 的 data-label,每行的首格留空当小标题(如地点名),操作格给「操作」。 + 表格结构与脚本都没动(只是隐藏 thead),链接 / 表单 / 按钮照旧;断点跟其它移动端适配一致 + (620px),桌面与平板仍是原来的表格,一行不差。 + 注:统计页那几张表在宽屏也被放在 g2 的窄卡片里(视口 1440 时卡片只有 494px),仍然要横滑 + 100+px —— 但那属于桌面版式,真要治得单说;这里先只管移动端(按容器宽度判断会让这些卡片 + 在宽屏也竖排,实测把 /stats 撑高 1300px,得不偿失)。 */ +@media (max-width: 620px) { + .tw > table.tb.tb-stack { min-width: 0; } + .tw > table.tb.tb-stack thead { display: none; } + .tw > table.tb.tb-stack, + .tw > table.tb.tb-stack > tbody, + .tw > table.tb.tb-stack > tbody > tr, + .tw > table.tb.tb-stack > tbody > tr > td { display: block; width: auto; } + .tw > table.tb.tb-stack > tbody > tr { + padding: 9px 11px; border-bottom: 1px solid var(--line-soft); + } + .tw > table.tb.tb-stack > tbody > tr:last-child { border-bottom: 0; } + /* 值用悬挂缩进:标签绝对定位在左边,值换行时对齐到值那一栏,而不是缩到标签下面 */ + .tw > table.tb.tb-stack > tbody > tr > td { + position: relative; padding: 2px 0 2px 5.6em; border-bottom: 0; + } + .tw > table.tb.tb-stack > tbody > tr > td::before { + content: attr(data-label); position: absolute; left: 0; top: 2px; + width: 5em; color: var(--text-3); font-size: 12px; + } + /* 首格是这一行的主角(地点名 / 天气 / 方式…):不缩进、字号抬一档当小标题 */ + .tw > table.tb.tb-stack > tbody > tr > td:not([data-label]) { + padding-left: 0; margin-bottom: 2px; font-size: 14px; + } + /* 数字列不必再右对齐(现在已经是「标签 + 值」两栏) */ + .tw > table.tb.tb-stack td.num { text-align: left; } +} + diff --git a/internal/web/tb_stack_test.go b/internal/web/tb_stack_test.go new file mode 100644 index 0000000..6d02e5b --- /dev/null +++ b/internal/web/tb_stack_test.go @@ -0,0 +1,94 @@ +package web + +import ( + "context" + "net/http" + "net/http/httptest" + "regexp" + "strconv" + "strings" + "testing" +) + +// TestStackedTablesHaveLabels 守住「窄屏宽表变一屏一行」这条改动的核心不变量: +// 每张打了 tb-stack 的表,窄屏会把表头藏起来、改成「字段名 + 值」竖排,字段名只能取自 +// td 的 data-label。少写一个标签,那一格在手机上就是没有名字的裸值——而桌面端一切正常, +// 很难发现(这轮就漏过两次:一张表的中间几行、后台两张表的「状态 / 对访客 / 操作」)。 +// 顺带钉住每行格子数 == 表头列数,否则说明模板结构歪了。 +// +// ROND_TEST_CONF=conf/app-test.ini ROND_SRC=data/xxx.rondbackup go test ./internal/web -run StackedTables -v +func TestStackedTablesHaveLabels(t *testing.T) { + f := newMovementFixture(t) + + var topicID int64 + if err := f.pg.QueryRowContext(f.ctx, `SELECT id FROM topics WHERE dataset_id=$1 ORDER BY id LIMIT 1`, + f.dsID).Scan(&topicID); err != nil { + topicID = 0 // 这个数据集没有专题,就少查一页 + } + + type target struct { + path string + h http.HandlerFunc + admin bool + } + targets := []target{ + {"/places", f.srv.placesPage, false}, + {"/stats", f.srv.statsPage, false}, + {"/", f.srv.home, false}, + {"/report", f.srv.reportPage, false}, + {"/admin", f.srv.adminHome, true}, + {"/admin/topics", f.srv.topicsAdminPage, true}, + } + if topicID > 0 { + targets = append(targets, target{"/topics/" + strconv.FormatInt(topicID, 10), f.srv.topicPage, false}) + } + + tableRe := regexp.MustCompile(`(?s)
| 文件 | 导入时间 | 到访 | 地点 | 数据跨度 | 状态 | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{trunc .Name 34}} | -{{dt .UploadedAt}} | -{{num .Visits}} | -{{num .Places}} | -{{if .First}}{{d .First}} ~ {{d .Last}}{{else}}—{{end}} | -+ | {{dt .UploadedAt}} | +{{num .Visits}} | +{{num .Places}} | +{{if .First}}{{d .First}} ~ {{d .Last}}{{else}}—{{end}} | +{{if and $.Dataset (eq $.Dataset.ID .ID)}} 展示中 {{else}} 未启用 {{end}} | -+ | {{if not (and $.Dataset (eq $.Dataset.ID .ID))}} |