diff --git a/admin/main_test.go b/admin/main_test.go index 2e67e80..3463fa0 100644 --- a/admin/main_test.go +++ b/admin/main_test.go @@ -336,7 +336,7 @@ func TestSybPage_紧凑筛选和可见横向滚动(t *testing.T) { `class="table-wrap syb-table-wrap"`, `class="syb-col-shop"`, `class="syb-col-spec"`, - `colspan="12"`, + `colspan="11"`, } { if !strings.Contains(pageText, want) { t.Errorf("顺运宝紧凑列表缺少 %q", want) @@ -345,6 +345,8 @@ func TestSybPage_紧凑筛选和可见横向滚动(t *testing.T) { for _, removed := range []string{ `href="/shops">店铺管理(同步`, `货运单 ID`, + `处理阶段`, + `按顺运宝货运单创建日期(UTC+8)同步`, `每行只显示当前最需要完成的下一步`, } { if strings.Contains(pageText, removed) { @@ -359,10 +361,15 @@ func TestSybPage_紧凑筛选和可见横向滚动(t *testing.T) { `.syb-col-spec`, `max-width: 140px`, `.syb-table-wrap`, - `max-height: calc(100vh - 270px)`, + `flex: 1 1 auto`, + `min-height: 0`, + `max-height: none`, `overflow: auto`, `.syb-table-wrap thead th`, `position: sticky`, + `body.syb-page-body`, + `height: 100dvh`, + `body.syb-page-body > .page`, } { if !strings.Contains(string(css), want) { t.Errorf("顺运宝紧凑列表样式缺少 %q", want) @@ -371,6 +378,9 @@ func TestSybPage_紧凑筛选和可见横向滚动(t *testing.T) { if !strings.Contains(string(header), `href="/shops"`) { t.Error("移除顺运宝工具条入口后,管理员主导航仍应保留店铺管理模块") } + if !strings.Contains(string(header), `class="syb-page-body"`) { + t.Error("顺运宝页面缺少专用视口布局类") + } } func TestShops_单一名称和状态且保护删除(t *testing.T) { @@ -610,7 +620,6 @@ func TestMainPagesReturnOK(t *testing.T) { `data-history-fetch-url=`, `name="date_from"`, `name="date_to"`, `name="stage"`, "处理阶段", `name="shop"`, "店铺", "下一步", `data-detail-url=`, - "按顺运宝货运单创建日期(UTC+8)同步", "创建真实采购任务", "所有当前账号可见的客户端均可指派", } { if !strings.Contains(sybResponse.Body.String(), want) { @@ -630,6 +639,11 @@ func TestMainPagesReturnOK(t *testing.T) { if strings.Contains(sybResponse.Body.String(), "指定日期同步") { t.Error("顺运宝页面不应再显示旧的指定日期同步入口") } + for _, removed := range []string{"按顺运宝货运单创建日期(UTC+8)同步", `处理阶段`} { + if strings.Contains(sybResponse.Body.String(), removed) { + t.Errorf("顺运宝页面仍包含已移除内容 %q", removed) + } + } for _, removed := range []string{`name="execution_mode"`, "采购演练", "仅演练", "支持真实下单", "真实下单安全确认", `name="live_acknowledged"`, `name="live_confirmation"`, `data-confirm-submit=`} { if strings.Contains(sybResponse.Body.String(), removed) { diff --git a/admin/service/syb.go b/admin/service/syb.go index 96833e3..2436c6a 100644 --- a/admin/service/syb.go +++ b/admin/service/syb.go @@ -1133,11 +1133,11 @@ func sybStageFor(c repository.SybOrderContext) (stage, text, help, action string case c.HasSucceededPurchaseTask: return SybStagePurchaseCompleted, "采购完成", "采购任务已成功完成,请到采集采购页面查看 PDD 订单编号和下单时间。", "查看采购结果" case c.HasManualReviewPurchaseTask: - return SybStagePurchaseReview, "采购待人工核对", "任务可能已经下单,必须先核对订单,禁止重新创建采购任务。", "查看采购任务" + return SybStagePurchaseReview, "采购待人工核对", "任务可能已经下单,必须先核对订单,禁止重新创建采购任务。", "核对采购订单" case c.HasActiveTask: return SybStageTaskCreated, "已创建采购任务", "已有未结束的采购任务,请到采集采购页面查看。", "查看采购任务" case c.Order.SpecKey == "": - return SybStageSpecMissing, "采购数据异常:顺运宝未提供规格", "缺少规格原文,不能匹配或创建采购任务。", "核对数据" + return SybStageSpecMissing, "采购数据异常:顺运宝未提供规格", "缺少规格原文,不能匹配或创建采购任务。", "核对缺失规格" case c.PddGoodsID == "" || c.PddCollectStatus == "": return SybStagePddMissing, "未关联 PDD", "下一步关联采购商品。", "关联 PDD" case c.PddCollectStatus == string(model.CollectPending): @@ -1155,7 +1155,7 @@ func sybStageFor(c repository.SybOrderContext) (stage, text, help, action string case !mappingIsValid(c): return SybStageMappingPending, "规格待匹配", "PDD 数据已采集,下一步匹配采购规格。", "匹配规格" case c.Order.Quantity <= 0: - return SybStagePurchaseBlocked, "采购数据异常", "顺运宝采购数量不是正数,不能创建采购任务。", "核对数据" + return SybStagePurchaseBlocked, "采购数据异常", "顺运宝采购数量不是正数,不能创建采购任务。", "核对采购数量" default: return SybStagePurchaseReady, "可创建采购任务", "规格映射有效,可以创建采购任务。", "创建采购任务" } diff --git a/admin/service/syb_workflow_test.go b/admin/service/syb_workflow_test.go index b682610..4429462 100644 --- a/admin/service/syb_workflow_test.go +++ b/admin/service/syb_workflow_test.go @@ -110,7 +110,7 @@ func TestSybStageFor_全部筛选阶段与逐行推导一致(t *testing.T) { action string context repository.SybOrderContext }{ - {SybStageSpecMissing, "核对数据", copyWith(func(c *repository.SybOrderContext) { c.Order.SpecKey = "" })}, + {SybStageSpecMissing, "核对缺失规格", copyWith(func(c *repository.SybOrderContext) { c.Order.SpecKey = "" })}, {SybStagePddMissing, "关联 PDD", copyWith(func(c *repository.SybOrderContext) { c.PddGoodsID, c.PddCollectStatus = "", "" })}, {SybStagePddPending, "创建采集任务", copyWith(func(c *repository.SybOrderContext) { c.PddCollectStatus = string(model.CollectPending) })}, {SybStagePddCollecting, "查看采集状态", copyWith(func(c *repository.SybOrderContext) { @@ -129,11 +129,11 @@ func TestSybStageFor_全部筛选阶段与逐行推导一致(t *testing.T) { c.HasSucceededPurchaseTask, c.HasManualReviewPurchaseTask = true, true c.Order.SpecKey = "" })}, - {SybStagePurchaseReview, "查看采购任务", copyWith(func(c *repository.SybOrderContext) { + {SybStagePurchaseReview, "核对采购订单", copyWith(func(c *repository.SybOrderContext) { c.HasManualReviewPurchaseTask = true c.MappingOptionKey = "" })}, - {SybStagePurchaseBlocked, "核对数据", copyWith(func(c *repository.SybOrderContext) { c.Order.Quantity = 0 })}, + {SybStagePurchaseBlocked, "核对采购数量", copyWith(func(c *repository.SybOrderContext) { c.Order.Quantity = 0 })}, {SybStagePurchaseReady, "创建采购任务", ready}, } if got := len(SybStageOptions()) - 1; got != len(cases) { diff --git a/admin/static/css/app.css b/admin/static/css/app.css index d84cec0..c9636a1 100644 --- a/admin/static/css/app.css +++ b/admin/static/css/app.css @@ -79,6 +79,23 @@ body { /* ── 页面主体 ─────────────────────────── */ .page { padding: 16px; } +/* 顺运宝是高密度操作表:桌面端让主区域占满导航和固定状态栏之间的空间, + 工具条或条件提示高度变化时,表格自动取得剩余高度,不依赖固定像素扣减。 */ +body.syb-page-body { + height: 100vh; + height: 100dvh; + display: flex; + flex-direction: column; + overflow: hidden; +} +body.syb-page-body > .nav { flex: 0 0 auto; } +body.syb-page-body > .page { + flex: 1 1 auto; + min-height: 0; + display: flex; + flex-direction: column; +} + /* ── 第一段:顶部工具条 ───────────────── */ .toolbar { display: flex; @@ -256,7 +273,9 @@ tr.empty small { color: #aaa; } max-width: 140px; } .syb-table-wrap { - max-height: calc(100vh - 270px); + flex: 1 1 auto; + min-height: 0; + max-height: none; overflow: auto; scrollbar-gutter: stable; } @@ -266,6 +285,13 @@ tr.empty small { color: #aaa; } z-index: 1; } @media (max-width: 760px) { + body.syb-page-body { + height: auto; + min-height: 100dvh; + display: block; + overflow: auto; + } + body.syb-page-body > .page { display: block; } .syb-table-wrap { max-height: none; } } diff --git a/admin/syb_interaction_template_test.go b/admin/syb_interaction_template_test.go index 5b3c758..9d4356b 100644 --- a/admin/syb_interaction_template_test.go +++ b/admin/syb_interaction_template_test.go @@ -35,7 +35,7 @@ func TestSybListTemplate_区分标题图片与阶段动作(t *testing.T) { { SybID: "SYB-REVIEW", OrderNo: "ORDER-REVIEW", Title: "待核对商品", Stage: service.SybStagePurchaseReview, StageText: "采购待人工核对", - StageHelp: "禁止重新采购", ActionText: "查看采购任务", + StageHelp: "禁止重新采购", ActionText: "核对采购订单", }, { SybID: "SYB-PDD", OrderNo: "ORDER-PDD", Title: "待关联商品", @@ -90,10 +90,13 @@ func TestSybListTemplate_区分标题图片与阶段动作(t *testing.T) { `href="/syb?date_from=2026-08-12`, `date_to=2026-08-13">清除`, `class="table-wrap syb-table-wrap"`, + `class="syb-page-body"`, `店铺`, `规格`, `value="SYB-READY" name="ids"`, `同一 PDD 商品关联多条货运单时只创建一条任务`, + `>核对采购订单`, + `title="禁止重新采购"`, `title="当前阶段不能批量操作:下一步关联采购商品"`, } { if !strings.Contains(body, want) { @@ -105,10 +108,12 @@ func TestSybListTemplate_区分标题图片与阶段动作(t *testing.T) { } for _, removed := range []string{ `货运单 ID`, + `处理阶段`, `SYB-READY`, `>创建 PDD 采集任务`, `

创建 PDD 采集任务

`, `每行只显示当前最需要完成的下一步`, + `按顺运宝货运单创建日期(UTC+8)同步`, } { if strings.Contains(body, removed) { t.Errorf("顺运宝列表仍包含已移除内容 %q", removed) diff --git a/admin/templates/partials/header.html b/admin/templates/partials/header.html index d9a9a46..69aa735 100644 --- a/admin/templates/partials/header.html +++ b/admin/templates/partials/header.html @@ -6,7 +6,7 @@ {{.Title}} · 采集采购管理端 - +