style: 优化顺运宝列表筛选与滚动 (#216)

This commit is contained in:
chengma
2026-08-13 14:21:37 +08:00
parent 282a917936
commit 40f62208b6
6 changed files with 145 additions and 31 deletions
+57
View File
@@ -316,6 +316,63 @@ func TestSybPage_明确展示蝦皮商品Pdd关联来源(t *testing.T) {
}
}
func TestSybPage_紧凑筛选和可见横向滚动(t *testing.T) {
page, err := os.ReadFile("templates/syb/list.html")
if err != nil {
t.Fatal(err)
}
css, err := os.ReadFile("static/css/app.css")
if err != nil {
t.Fatal(err)
}
header, err := os.ReadFile("templates/partials/header.html")
if err != nil {
t.Fatal(err)
}
pageText := string(page)
for _, want := range []string{
`class="syb-search-input"`,
`>清除</a>`,
`class="table-wrap syb-table-wrap"`,
`class="syb-col-shop"`,
`class="syb-col-spec"`,
`colspan="12"`,
} {
if !strings.Contains(pageText, want) {
t.Errorf("顺运宝紧凑列表缺少 %q", want)
}
}
for _, removed := range []string{
`href="/shops">店铺管理(同步`,
`<th>货运单 ID</th>`,
`每行只显示当前最需要完成的下一步`,
} {
if strings.Contains(pageText, removed) {
t.Errorf("顺运宝列表仍包含已移除内容 %q", removed)
}
}
for _, want := range []string{
`.toolbar input[type="text"].syb-search-input`,
`flex: 0 0 140px`,
`.syb-col-shop`,
`max-width: 224px`,
`.syb-col-spec`,
`max-width: 140px`,
`.syb-table-wrap`,
`max-height: calc(100vh - 270px)`,
`overflow: auto`,
`.syb-table-wrap thead th`,
`position: sticky`,
} {
if !strings.Contains(string(css), want) {
t.Errorf("顺运宝紧凑列表样式缺少 %q", want)
}
}
if !strings.Contains(string(header), `href="/shops"`) {
t.Error("移除顺运宝工具条入口后,管理员主导航仍应保留店铺管理模块")
}
}
func TestShops_单一名称和状态且保护删除(t *testing.T) {
templateContent, err := os.ReadFile("templates/shop/list.html")
if err != nil {
+29
View File
@@ -112,6 +112,11 @@ body {
用 flex 而不是 width:工具条是 flex 布局,width 会被 flex-grow 盖掉。
min-width 由下面那条继承,窄屏时不会缩到没法输入。 */
.toolbar input[type="text"].search-narrow { flex: 0 0 30%; }
/* 顺运宝一行需要容纳两个搜索框和操作按钮,固定宽度比百分比更稳定。 */
.toolbar input[type="text"].syb-search-input {
flex: 0 0 140px;
min-width: 140px;
}
/* 蝦皮工具条同时放商品和店铺两个搜索框,各占剩余工具条的约 20%。
min-width 继续由通用输入框规则提供,窄窗口时交给工具条自然换行。 */
.toolbar input[type="text"].shopee-search-field { flex: 0 1 20%; }
@@ -240,6 +245,30 @@ tr.empty small { color: #aaa; }
text-overflow: ellipsis;
}
/* 顺运宝列很多:限制高频短字段宽度,并让表头和横向滚动条在浏览数据时
始终容易找到。syb_id 仍保留在复选框和详情入口中,不作为独立列展示。 */
.syb-col-shop {
width: 224px;
max-width: 224px;
}
.syb-col-spec {
width: 140px;
max-width: 140px;
}
.syb-table-wrap {
max-height: calc(100vh - 270px);
overflow: auto;
scrollbar-gutter: stable;
}
.syb-table-wrap thead th {
position: sticky;
top: 0;
z-index: 1;
}
@media (max-width: 760px) {
.syb-table-wrap { max-height: none; }
}
/* 蝦皮数据页商品名称列收窄,配合 .truncate 一起用(见工单 #214)。
用独立类设 max-width,不用 flex——.search-narrow 那套是给工具条用的,
表格单元格不是 flex 布局,flex 在这里不生效。放在 .truncate 之后,
+21
View File
@@ -55,6 +55,7 @@ func TestSybListTemplate_区分标题图片与阶段动作(t *testing.T) {
"Title": "顺运宝数据", "Active": "syb", "CSRFToken": "test-csrf",
"Rows": rows, "PurchaseRows": rows,
"DetailURL": "/syb/detail", "StageOptions": service.SybStageOptions(),
"SyncDateFrom": "2026-08-12", "SyncDateTo": "2026-08-13",
}
if err := tmpl.ExecuteTemplate(&output, "syb/list", data); err != nil {
t.Fatalf("渲染顺运宝列表失败: %v", err)
@@ -83,6 +84,15 @@ func TestSybListTemplate_区分标题图片与阶段动作(t *testing.T) {
`data-select-action="collect"`,
`form="syb-collect-form"`,
`id="syb-collect-modal"`,
`>创建采集任务</button>`,
`<h2 id="syb-collect-modal-title">创建采集任务</h2>`,
`class="syb-search-input"`,
`href="/syb?date_from=2026-08-12`,
`date_to=2026-08-13">清除</a>`,
`class="table-wrap syb-table-wrap"`,
`<th class="syb-col-shop">店铺</th>`,
`<th class="syb-col-spec">规格</th>`,
`value="SYB-READY" name="ids"`,
`同一 PDD 商品关联多条货运单时只创建一条任务`,
`title="当前阶段不能批量操作:下一步关联采购商品"`,
} {
@@ -93,6 +103,17 @@ func TestSybListTemplate_区分标题图片与阶段动作(t *testing.T) {
if strings.Contains(body, `<tr data-detail-id=`) {
t.Error("顺运宝列表不应继续使用含义模糊的整行双击入口")
}
for _, removed := range []string{
`<th>货运单 ID</th>`,
`<td>SYB-READY</td>`,
`>创建 PDD 采集任务</button>`,
`<h2 id="syb-collect-modal-title">创建 PDD 采集任务</h2>`,
`每行只显示当前最需要完成的下一步`,
} {
if strings.Contains(body, removed) {
t.Errorf("顺运宝列表仍包含已移除内容 %q", removed)
}
}
}
func TestSybDetailTemplate_单条采集可选执行客户端(t *testing.T) {
+11 -19
View File
@@ -21,7 +21,6 @@
</form>
<button type="button" data-modal-open="sync-history-modal">同步记录</button>
{{if .CurrentUser.IsAdmin}}<a class="button-link" href="/shops">店铺管理(同步 {{.EnabledSyncShopCount}})</a>{{end}}
<form id="syb-collect-form" method="post" action="/syb/collect-pdd-batch" hidden></form>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}" form="syb-collect-form">
@@ -31,7 +30,7 @@
<input type="hidden" name="page" value="{{.CurrentPage}}" form="syb-collect-form">
<button type="button" data-modal-open="syb-collect-modal" data-collect-open
data-collect-form="syb-collect-form" data-collect-action="collect"
data-need-checked="collect">创建 PDD 采集任务</button>
data-need-checked="collect">创建采集任务</button>
<button type="button" data-need-checked="purchase" data-modal-open="purchase-modal"
data-purchase-open>创建采购任务</button>
@@ -45,12 +44,11 @@
</select>
<label for="shop">店铺</label>
<input id="shop" type="text" name="shop" value="{{.ShopFilter}}"
class="search-narrow" placeholder="店铺名">
class="syb-search-input" placeholder="店铺名">
<label for="q">订单号</label>
{{/* search-narrow 把搜索框收到 30%,让「搜索」按钮紧挨着它。
用类名而不是改 .toolbar input[type="text"]——那条被五个页面共用。 */}}
<input id="q" type="text" name="order_no" value="{{.Keyword}}"
class="search-narrow" placeholder="订单号">
class="syb-search-input" placeholder="订单号">
<a class="button-link" href="/syb?date_from={{urlquery .SyncDateFrom}}&date_to={{urlquery .SyncDateTo}}">清除</a>
<button type="submit">搜索</button>
</form>
@@ -98,16 +96,15 @@
<p class="hint">{{.LoginHint}}</p>
{{end}}
<div class="table-wrap">
<div class="table-wrap syb-table-wrap">
<table>
<thead>
<tr>
<th class="col-check"><input type="checkbox" data-check-all></th>
<th>货运单 ID</th>
<th>订单号</th>
<th>店铺</th>
<th class="syb-col-shop">店铺</th>
<th>商品标题</th>
<th>规格</th>
<th class="syb-col-spec">规格</th>
<th>蝦皮商品 ID</th>
<th>数量</th>
<th>价格</th>
@@ -129,14 +126,13 @@
aria-label="选择货运单明细 {{.SybID}}:{{.SelectionHint}}">
</span>
</td>
<td>{{.SybID}}</td>
<td>{{.OrderNo}}</td>
<td class="truncate" title="{{.ShopName}}">{{if .ShopName}}{{.ShopName}}{{else}}—{{end}}</td>
<td class="truncate syb-col-shop" title="{{.ShopName}}">{{if .ShopName}}{{.ShopName}}{{else}}—{{end}}</td>
<td class="truncate" title="{{.Title}}">
<button type="button" class="table-title-action" data-detail-open-id="{{.SybID}}"
title="打开商品处理详情">{{.Title}}</button>
</td>
<td class="truncate" title="{{.ProductSpec}}">{{.ProductSpec}}</td>
<td class="truncate syb-col-spec" title="{{.ProductSpec}}">{{.ProductSpec}}</td>
<td>{{.ShopeeGoodsID}}</td>
<td>{{.Quantity}}</td>
<td>{{.PriceText}}</td>
@@ -165,7 +161,7 @@
</tr>
{{else}}
<tr class="empty">
<td colspan="13">
<td colspan="12">
{{if .IsFiltered}}
当前筛选条件下没有货运单明细。<br>
<small>换个店铺、订单号或清空筛选条件再试。<a href="/syb">查看全部</a></small>
@@ -183,7 +179,7 @@
<div class="modal-backdrop" id="syb-collect-modal" hidden>
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="syb-collect-modal-title">
<div class="modal-head">
<h2 id="syb-collect-modal-title">创建 PDD 采集任务</h2>
<h2 id="syb-collect-modal-title">创建采集任务</h2>
<button type="button" class="modal-x" data-modal-close aria-label="关闭">×</button>
</div>
<div class="modal-body">
@@ -262,10 +258,6 @@
</div>
</div>
<p class="hint">
每行只显示当前最需要完成的下一步;点击商品标题进入处理详情,点击图片查看原图。
</p>
<div class="modal-backdrop" id="image-preview-modal" hidden>
<div class="modal image-preview-modal" role="dialog" aria-modal="true"
aria-labelledby="image-preview-title">