diff --git a/internal/web/static/css/app.css b/internal/web/static/css/app.css index a066039..a35235f 100644 --- a/internal/web/static/css/app.css +++ b/internal/web/static/css/app.css @@ -117,6 +117,13 @@ h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -.01em; } .brand .t { display: none; } .nav-links { overflow-x: auto; scrollbar-width: none; gap: 0; } .nav-links::-webkit-scrollbar { display: none; } + /* 还能往右滑的时候右缘渐隐一下(由 nav 后面那几行脚本按 scrollLeft 加/去这个类)。 + 用 mask 而不是盖一层渐变伪元素:伪元素会把链接文字一起遮住,mask 是让内容本身渐隐。 + 不支持 mask 的浏览器只是少个提示,滑动照旧。 */ + .nav-links.overflow-right { + -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); + mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); + } .nav-links a { padding: 5px 7px; font-size: 13px; } .nav-right .who { display: none; } .nav-right .btn.sm { padding: 4px 9px; font-size: 12.5px; } @@ -284,6 +291,10 @@ table.tb th { padding: 7px 10px; border-bottom: 1px solid var(--line); white-space: nowrap; } table.tb td { padding: 9px 10px; border-bottom: 1px solid var(--line-soft); } +/* 操作列(桌面要横着一排按钮,不折行)。原来是写在模板上的 inline style,而 white-space 会 + 继承进行内编辑表单,堆叠态下「已选:…重选」那一行就顶破了卡片——inline 又压不过后面的覆盖, + 所以挪成类,放不下宽表时在文件末尾统一放开。 */ +table.tb td.ops { white-space: nowrap; } table.tb tr:hover td { background: var(--row-hover); } table.tb td.num, table.tb th.num { text-align: right; font-variant-numeric: tabular-nums; } .tw { overflow-x: auto; } @@ -807,7 +818,9 @@ footer.ft { max-width: 1120px; margin: 0 auto; padding: 20px; color: var(--text- .inline-edit summary { list-style: none; display: inline-block; } .inline-edit summary::-webkit-details-marker { display: none; } .inline-edit[open] { display: block; } -.inline-edit form { background: var(--bg-2, #fafbfb); border: 1px solid var(--line); border-radius: 10px; padding: 12px; } +/* 行内编辑表单的宽度:桌面靠 --efw 撑到够填(各表不同,见模板里的 inline 变量), + 放不下宽表时下面会放开这个下限——不然 320px 的表单会把 294px 的卡片顶破。 */ +.inline-edit form { background: var(--bg-2, #fafbfb); border: 1px solid var(--line); border-radius: 10px; padding: 12px; min-width: var(--efw, 280px); } .inline-edit form .f { margin-bottom: 8px; } /* 「按名称搜坐标」输入框 + 按钮:必须始终同一行(含移动端),底边对齐。 @@ -1008,16 +1021,19 @@ label.f > span.span-actions { display: flex; align-items: center; justify-conten .filters-card.collapsed > :not(.panel-fold) { display: none; } } -/* ---------- 窄屏:要横滑的宽表改成一屏一行的「字段 + 值」 ---------- - 地点库(8 列)、统计、专题、后台这几张表在手机上要横滑 300+px 才看得全,滑着还对不上表头。 - 窄屏改成每行一块、每格「字段名 + 值」竖排:不用横滑,也不用记「第几列是什么」。 +/* ---------- 放不下宽表时:一屏一行的「字段 + 值」 ---------- + 地点库(8 列)、统计、专题、后台这几张表在窄处要横滑 300+px 才看得全,滑着还对不上表头。 + 放不下时改成每行一块、每格「字段名 + 值」竖排:不用横滑,也不用记「第几列是什么」。 字段名取 td 的 data-label,每行的首格留空当小标题(如地点名),操作格给「操作」。 - 表格结构与脚本都没动(只是隐藏 thead),链接 / 表单 / 按钮照旧;断点跟其它移动端适配一致 - (620px),桌面与平板仍是原来的表格,一行不差。 - 注:统计页那几张表在宽屏也被放在 g2 的窄卡片里(视口 1440 时卡片只有 494px),仍然要横滑 - 100+px —— 但那属于桌面版式,真要治得单说;这里先只管移动端(按容器宽度判断会让这些卡片 - 在宽屏也竖排,实测把 /stats 撑高 1300px,得不偿失)。 */ -@media (max-width: 620px) { + 表格结构与脚本都没动(只是隐藏 thead),链接 / 表单 / 按钮照旧。 + 阈值 800 是从「卡片能不能放下表格」换算来的:卡片内容宽 ≈ 视口 − 93(页面 + 卡片的内边距), + 这几张表的 min-width 最宽是 700 ⇒ 视口 793 以上才放得下,取 800 留几像素余量。 + **必须用 @media,别改成 @container**:容器查询能按「卡片自己有多宽」判得更准,可它要 + iOS 16 / Chrome 105 起才支持——旧手机整块规则直接失效,表格完全不堆叠、退化成横滑 + 328~388px(2026-09-19 真机上就是这么炸的,比改之前还糟)。现在宽表卡片已被要求不放 g2 + (见 wide_table_layout_test.go),卡片宽度只由视口决定,两种判据在这些页面上等价, + 那就用兼容性好的那个。若页面/卡片的内边距变了,这里的 800 要跟着重算。 */ +@media (max-width: 800px) { .tw > table.tb.tb-stack { min-width: 0; } .tw > table.tb.tb-stack thead { display: none; } .tw > table.tb.tb-stack, @@ -1036,11 +1052,21 @@ label.f > span.span-actions { display: flex; align-items: center; justify-conten content: attr(data-label); position: absolute; left: 0; top: 2px; width: 5em; color: var(--text-3); font-size: 12px; } - /* 首格是这一行的主角(地点名 / 天气 / 方式…):不缩进、字号抬一档当小标题 */ + /* 首格是这一行的主角(地点名 / 天气 / 方式…):不缩进、字号抬一档当小标题; + 操作格也是这一类(表头为空、整行铺开)。它们里面的内容是长名称或编辑表单, + 而桌面模板给操作格挂了 nowrap(那一列要横向排按钮)——white-space 会继承到表单里, + 于是「已选:#403 2026-09-13 19:53 · 某某地」这一行在窄处不换行、把卡片顶出 44px。 + 堆叠态每格本来就是一整行,nowrap 没有意义,放开。 */ .tw > table.tb.tb-stack > tbody > tr > td:not([data-label]) { - padding-left: 0; margin-bottom: 2px; font-size: 14px; + padding-left: 0; margin-bottom: 2px; font-size: 14px; white-space: normal; } + /* 操作格(有的带「操作」标签、有的表头本来就是空的)在堆叠态整行铺开, + 桌面那条 nowrap 会让格里的编辑表单不换行、把卡片顶出几十像素 */ + .tw > table.tb.tb-stack > tbody > tr > td.ops { white-space: normal; } /* 数字列不必再右对齐(现在已经是「标签 + 值」两栏) */ .tw > table.tb.tb-stack td.num { text-align: left; } + /* 行内编辑表单的桌面宽度下限在这里放开:320px 的表单加上悬挂缩进会顶破卡片, + 而表单字段本来就是 flex 自适应的(见 .row / label.f),窄处自然铺满即可。 */ + .tw > table.tb.tb-stack .inline-edit form { min-width: 0; } } diff --git a/internal/web/tb_stack_test.go b/internal/web/tb_stack_test.go index 6d02e5b..733bc68 100644 --- a/internal/web/tb_stack_test.go +++ b/internal/web/tb_stack_test.go @@ -38,6 +38,8 @@ func TestStackedTablesHaveLabels(t *testing.T) { {"/report", f.srv.reportPage, false}, {"/admin", f.srv.adminHome, true}, {"/admin/topics", f.srv.topicsAdminPage, true}, + // 数据编辑页的三张表默认折叠在卡片里(探针量到的是 display:none),最容易漏标 + {"/admin/edit", f.srv.editPage, true}, } if topicID > 0 { targets = append(targets, target{"/topics/" + strconv.FormatInt(topicID, 10), f.srv.topicPage, false}) @@ -47,6 +49,8 @@ func TestStackedTablesHaveLabels(t *testing.T) { rowRe := regexp.MustCompile(`(?s)]*>(.*?)`) tdRe := regexp.MustCompile(`(?s)]*)>`) thRe := regexp.MustCompile(`]`) + thTextRe := regexp.MustCompile(`(?s)]*>(.*?)`) + tagStripRe := regexp.MustCompile(`<[^>]*>`) total := 0 for _, tg := range targets { @@ -67,6 +71,14 @@ func TestStackedTablesHaveLabels(t *testing.T) { head = tb[i:j] } cols := len(thRe.FindAllString(head, -1)) + // 表头为空的列(如三张表末尾那个只放「编辑」的操作格)不需要名字:窄屏堆叠时 + // 它整行铺开,硬加个标签反而把按钮/表单挤窄。判据跟着表头走,两边自然一致。 + blank := make([]bool, cols) + if ths := thTextRe.FindAllStringSubmatch(head, -1); len(ths) == cols { + for i, th := range ths { + blank[i] = strings.TrimSpace(tagStripRe.ReplaceAllString(th[1], "")) == "" + } + } for ri, row := range rowRe.FindAllString(tb, -1) { if !strings.Contains(row, "共 {{num .Total}} 个地点,按到访数排序{{if .SuspectCount}};其中 {{num .SuspectCount}} 个的显示坐标疑似就是 WGS-84(当初没做偏移,底图上会偏 500 米左右),行内已标注{{end}}。「坐标来源」是建点时留下的记录:照片导入会把当时选的坐标系一起记下来,未留档的是 2026-09 之前的行,只能靠原图或行内标注判断。 {{if .Places}}
- +
{{range .Places}} - - + - - +
名称城市坐标到访
{{if .Name}}{{.Name}}{{else}}(未命名){{end}} #{{.SrcPK}}{{.City}}{{if .District}} · {{.District}}{{end}}{{if .Thoroughfare}} · {{.Thoroughfare}}{{end}}{{printf "%.5f" .Lat}}, {{printf "%.5f" .Lon}} + {{.City}}{{if .District}} · {{.District}}{{end}}{{if .Thoroughfare}} · {{.Thoroughfare}}{{end}}{{printf "%.5f" .Lat}}, {{printf "%.5f" .Lon}}
{{.SourceTag}} {{if .SuspectWGS}}疑似 WGS-84{{end}} {{if .MovedM}}
比导入时移动了 {{num .MovedM}} 米{{end}}
{{num .VisitCount}} + {{num .VisitCount}}
编辑 -
+