Spree Next.js 商店前端如何开启 B2B 批发门户并配置渠道门控模式?
2026/9/15 16:43:56 网站建设 项目流程

Spree Next.js 商店前端如何开启 B2B 批发门户并配置渠道门控模式?

【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree

Spree 的 Next.js 商店前端内置了一个可选的 B2B 批发门户(/wholesale路由)。它运行在一条单独的 Spree 销售渠道上,与面向公众的 DTC 商店共用同一套前端和 Spree 后端,一次部署即可同时服务零售访客和登录后可见批发价的贸易买家。本文以「已经跑通 Next.js 商店前端 + Spree 后端」为前提,说明如何打开这个批发门户,以及如何切换渠道的门控(gating)模式。

前提:渠道是端点门控的根源

批发门户本身不保存任何门控状态,全部访问控制由渠道的storefront_access属性决定。每个 Store API 请求都会解析到一条渠道:如果请求头携带X-Spree-Channel,则按channels.code(或ch_…前缀 ID)匹配当前 store 下的渠道;否则回退到 store 的默认渠道。渠道解析后,其storefront_access决定了未登录访客能看到什么,这个限制由Store API 强制,前端无法放宽它。

storefront_access有三种取值(渠道未设置时,继承所属 Store 的值,两者都未设置时最终落到public):

模式访客看目录访客看价格访客可下单
login_required否 — 读取直接返回401,展示登录墙
prices_hidden是 — 只读浏览否 — 金额字段返回null,前端渲染为「sign in for pricing」否 —「sign in to order」
public是(受guest_checkout控制)

批发门户支持前两种门控模式;public是 DTC 开放渠道的姿态,批发渠道通常不用。渠道上的guest_checkout(无账户能否下单)独立于storefront_access解析,两者分开设置。

如果还没有批发渠道,在管理后台Settings → Sales channels里新建一条渠道并记下它的code(保存时会自动归一化为 URL 安全的 slug,留空则从name派生)。后端种子数据默认会装一条login_required的批发渠道,code 为wholesale,直接复用即可。

第一步:为批发渠道设置门控模式

修改渠道的storefront_access即可在两种门控模式之间切换。用 Admin SDK(需要 secret keysk_xxx):

// 登录墙模式:访客完全不可见批发目录 await adminClient.channels.update('ch_wholesale', { storefront_access: 'login_required', guest_checkout: false, }) // 切换为 prices_hidden:访客可浏览目录但看不到价格 await adminClient.channels.update('ch_wholesale', { storefront_access: 'prices_hidden', }) // 将渠道值清空,继承 store 级默认 await adminClient.channels.update('ch_wholesale', { storefront_access: null, })

对应 HTTP 请求(ch_wholesale换成你的渠道 ID):

curl -X PATCH 'https://api.mystore.com/api/v3/admin/channels/ch_wholesale' \ -H 'X-Spree-API-Key: sk_xxx' \ -H 'Content-Type: application/json' \ -d '{ "storefront_access": "login_required", "guest_checkout": false }'

切换模式即时生效:姿态是按请求解析的,不需要预热缓存,也不需要重新部署前端。两种模式下登录和注册走的都是同一套审批流程。

Store API 请求时的渠道解析与 storefront_access 门控

第二步:在商店前端开启批发门户

批发门户是默认关闭的 opt-in 插件:不配置时,商店只做 DTC — 批发导航链接、页脚链接、首页分区全部隐藏,所有/wholesale路由返回 404。开启只需一个环境变量。

商店前端的配置写在.env.local(从.env.example复制起步):

# .env.local —— 批发门户环境变量 SPREE_API_URL=https://api.mystore.com # 必需,已有的 Spree API 端点 SPREE_PUBLISHABLE_KEY=pk_xxx # 必需,已有的 publishable key SPREE_WHOLESALE_CHANNEL=wholesale # 开启开关:指向后端批发渠道的 code # SPREE_WHOLESALE_PUBLISHABLE_KEY=pk_xxx # 可选,见下
  • SPREE_WHOLESALE_CHANNEL:开启开关。设为后端某条已门控渠道的 code(如上例的wholesale)。没有默认值:未设置时批发 UI 全部不渲染,/wholesale路由 404。
  • SPREE_WHOLESALE_PUBLISHABLE_KEY:可选。渠道头本身就能选中渠道,所以它回退到SPREE_PUBLISHABLE_KEY;只有当你想把批发面绑定到渠道级 publishable key 时才需要设置。

后端渠道的 code 必须与SPREE_WHOLESALE_CHANNEL的值一致。如果脚手架时用了create-spree-app的 sample-data 模板,它会自动把SPREE_WHOLESALE_CHANNEL=wholesale写进商店.env.local,并使用默认 publishable key 运行门户——不需要额外 key 或后端改动。

门户的工作机制是「surface」:批发 surface 持有自己绑定的 SDK 客户端,每个请求都带X-Spree-Channel: wholesale头:

import { createClient } from '@spree/sdk' const wholesaleClient = createClient({ baseUrl: process.env.SPREE_API_URL, publishableKey: process.env.SPREE_PUBLISHABLE_KEY, channel: 'wholesale', // sent as X-Spree-Channel on every request })

因为每个 surface 有自己的客户端、购物车 cookie 和缓存键,同一个客户可以同时持有一个开放的 DTC 购物车和一个批发购物车而互不串扰;JWT 会话是共享的——购物车分开,登录态从不分开。

第三步:买家审批 —— 登录不等于可用

渠道门控只管「访客能看到多少」,还有一道独立的客户级检查:买家必须被批准才能享受贸易价。批准 = 加入Wholesale客户组,管理员把申请者加进这个组即完成审批。前端读取customers/mecustomer_groups后分三种状态渲染:

  • 访客login_required下看到登录/申请墙;prices_hidden下看到只读目录 + 价格提示。
  • 已登录但不在组内— 显示「申请审核中」状态。两种模式下,已认证但未批准的买家都无法按批发价交易。
  • 已登录且在组内— 看到完整门户:贸易目录、快速下单、批发购物车。

在管理后台把客户加入客户组的操作路径:Customers → Customer Groups → 目标组 → Add Customers,在侧边面板中搜索并选中客户,点击Add Selected;移除则勾选客户后点Remove from Group

贸易价按数量解锁:种子模型中,单行达到 10 件同款商品时才给贸易价(VolumeRule 按行项目匹配,不按整单)。该数量规则挂在后端的 Price List 上,前端只展示 API 对达标数量返回的批发价;未达标时回落到零售价,不会硬性阻断下单。

验证:确认门控与审批生效

配置完成后可以按下面逐项核对,全部基于 Store API 的公开行为:

  1. 门户是否已开启:带渠道头访问批发目录,不再 404,且返回的是批发渠道的目录;不带该头则命中默认渠道。
    curl 'https://api.mystore.com/api/v3/store/products' \ -H 'X-Spree-API-Key: pk_xxx' \ -H 'X-Spree-Channel: wholesale'
  2. login_required模式:未携带认证信息的未登录请求,对受保护读接口一律返回401(认证、密码重置、国家/币种等参考数据接口除外)。此时前端在受保护页面展示登录/申请墙。
  3. prices_hidden模式:未登录请求读取成功,但所有金额字段序列化为null
    curl 'https://api.mystore.com/api/v3/store/products' \ -H 'X-Spree-API-Key: pk_xxx' \ -H 'X-Spree-Channel: wholesale' # 响应中 price 相关字段应为 null
  4. 审批链路:用一个已登录但不在 Wholesale 组的账号访问门户,应看到「申请审核中」而非批发价;管理员将其加入 Wholesale 组后,同一账号即可看到贸易目录。前端依据的就是customers/me返回的customer_groups
  5. 贸易价:用已批准的买家账号,把某商品行数量加到 10 件(种子模型阈值),API 返回的价格切换到批发价;低于阈值则回落到零售价。

想直接跑通完整演示(已批准买家 + 带数量规则的批发 Price List),可以加载示例数据:

bin/rake spree:load_sample_data

它会创建一个演示买家wholesale@example.com(密码spree123)并加入 Wholesale 组,同时建立名为Wholesale的 Price List:带 10 件起购的 VolumeRule 和指向 Wholesale 组的 CustomerGroupRule,贸易价为该货币零售价打六折(40% off),且按变体 × 币种覆盖全目录。注意这是演示种子数据,生产环境请按自己的定价规则建 Price List(在 Admin Panel 的Products → Price Lists或经 Admin API 创建)。

边界与限制

  • 渠道门控由 Store API 强制执行,商店前端无法放宽它;切换模式即时生效,无需重新部署前端。
  • guest_checkoutstorefront_access是两个独立开关:一条public渠道也可以要求账户下单。
  • 登录从不跳过审批:已认证但未入组的买家在两种门控模式下都不能按批发价交易。
  • 批发渠道通常不应使用public姿态。
  • 门户是参考实现而非固定功能:同一套渠道 + surface + 门控构件也可以反过来把主 DTC 渠道门控起来(members-only 商店),或去掉公开目录只做登录优先的 B2B 商店;按 Wholesale Portal 中的模式自行改造。

进一步阅读:Channels — Storefront Access Gating、Stores — storefront access defaults、Pricing — Price Lists 与 Volume Rule、Store SDK: Configuration(setChannel与 channel 客户端选项)。

【免费下载链接】spreeOpen Source eCommerce Platform for B2B, Marketplace, and Enterprise. REST API, TypeScript SDK, and production-ready Next.js storefront. Self-host it. Own your stack. No vendor lock-in. Zero platform fees.项目地址: https://gitcode.com/GitHub_Trending/sp/spree

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询