|
|
@@ -0,0 +1,230 @@
|
|
|
+# categoryAttributeFilters 接口说明
|
|
|
+
|
|
|
+分类属性筛选接口,返回某个分类下可用于筛选的属性列表及其可选值(含各选项对应的产品数量)。
|
|
|
+
|
|
|
+## GraphQL 端点
|
|
|
+
|
|
|
+- 端点:`POST /api/graphql`
|
|
|
+- 认证头:`X-STOREFRONT-KEY`
|
|
|
+
|
|
|
+## 查询参数(args)
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 说明 |
|
|
|
+|------|------|------|------|
|
|
|
+| `slug` | String | 否 | 分类 slug(如 `ready-to-go-wig`)。不传时返回全部可筛选属性 |
|
|
|
+| `filter` | String | 否 | JSON 格式的已选筛选条件,用于重新计算各选项的产品数量(faceted search 联动) |
|
|
|
+| `first` | Int | 否 | 返回条数(从开头取) |
|
|
|
+| `last` | Int | 否 | 返回条数(从末尾取) |
|
|
|
+| `after` | String | 否 | 分页游标(从某位置之后开始) |
|
|
|
+| `before` | String | 否 | 分页游标(从某位置之前开始) |
|
|
|
+
|
|
|
+### `filter` 参数格式
|
|
|
+
|
|
|
+与 `categoryProducts` 接口一致,JSON 字符串:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "wig_color": { "match": "33" },
|
|
|
+ "price_from": 10,
|
|
|
+ "price_to": 212
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- 属性筛选:`{"属性code": {"match": "选项ID"}}`
|
|
|
+- 价格区间:`price_from` / `price_to`
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 返回结构
|
|
|
+
|
|
|
+```
|
|
|
+categoryAttributeFilters {
|
|
|
+ edges {
|
|
|
+ node { ... } # 每个可筛选属性
|
|
|
+ }
|
|
|
+ pageInfo { ... } # 分页信息
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 返回字段备注
|
|
|
+
|
|
|
+### 顶层
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| `edges` | 数组 | 可筛选属性列表(每条是一个属性) |
|
|
|
+| `pageInfo` | 对象 | 分页信息(`hasNextPage`、`endCursor`) |
|
|
|
+
|
|
|
+### `edges.node`(每个属性)
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| `_id` | Int | 属性数字 ID |
|
|
|
+| `code` | String | 属性编码(唯一标识,如 `wig_color`、`price`、`length`) |
|
|
|
+| `adminName` | String | 属性管理名称(后台配置的名称,如 "Wig Color") |
|
|
|
+| `type` | String | 属性类型(见下方"属性类型") |
|
|
|
+| `swatchType` | String | 色板类型(见下方"色板类型") |
|
|
|
+| `position` | Int | 属性排序位置(数字越小越靠前) |
|
|
|
+| `minPrice` | Float | 价格筛选最小值(仅 `price` 属性有效,其他属性为 0) |
|
|
|
+| `maxPrice` | Float | 价格筛选最大值(仅 `price` 属性有效) |
|
|
|
+| `options` | 数组 | 该属性的可选值列表(连接对象) |
|
|
|
+
|
|
|
+### `options.edges.node`(每个属性选项)
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| `_id` | Int | 选项数字 ID |
|
|
|
+| `adminName` | String | 选项名称(如 "33"、"Blonde"、"M") |
|
|
|
+| `sortOrder` | Int | 选项排序位置 |
|
|
|
+| `swatchValue` | String | 色板值(含义取决于父属性的 `swatchType`) |
|
|
|
+| `productCount` | Int | 该选项对应的产品数量(faceted search 联动计算) |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 字段值说明
|
|
|
+
|
|
|
+### 属性类型(`type`)
|
|
|
+
|
|
|
+| 值 | 说明 | 前端渲染建议 |
|
|
|
+|----|------|------------|
|
|
|
+| `select` | 下拉单选 | 单选列表 / 颜色筛选 |
|
|
|
+| `multiselect` | 多选 | 多选列表 |
|
|
|
+| `price` | 价格 | 价格区间滑块(用 `minPrice`/`maxPrice`) |
|
|
|
+| `boolean` | 布尔 | 开关 |
|
|
|
+| `text` | 文本 | 文本框 |
|
|
|
+| `textarea` | 多行文本 | 文本域 |
|
|
|
+| `date` / `datetime` | 日期 | 日期选择器 |
|
|
|
+
|
|
|
+### 色板类型(`swatchType`)
|
|
|
+
|
|
|
+| 值 | `swatchValue` 含义 |
|
|
|
+|----|------------------|
|
|
|
+| `color` | 颜色值(如 `#FF0000`),前端渲染为色块 |
|
|
|
+| `image` | 图片路径,前端渲染为图片 |
|
|
|
+| `text` | 文本标签 |
|
|
|
+
|
|
|
+### `productCount` 的联动说明(faceted search)
|
|
|
+
|
|
|
+- 当 `filter` 参数里传入了其他属性的筛选条件时,`productCount` 会根据**剩余匹配产品集**重新计算。
|
|
|
+- 用于实现"每选一个筛选项,其他筛选项的数量自动刷新"的效果。
|
|
|
+- 例如:选了 `wig_color=33` 后,`length` 属性各选项的 `productCount` 只统计"颜色为 33 的假发"。
|
|
|
+
|
|
|
+### `minPrice` / `maxPrice`
|
|
|
+
|
|
|
+- 只在 `price` 属性上有意义,从该分类下产品的价格索引(`product_price_indices`)聚合而来。
|
|
|
+- 用于前端渲染价格筛选区间的上下界。
|
|
|
+- 即使后台没有为分类配置 price 属性,接口也会自动补充一个 price 筛选(`ensurePriceFilter`)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 完整查询示例
|
|
|
+
|
|
|
+```graphql
|
|
|
+query getCategoryAttributeFilters($slug: String, $filter: String) {
|
|
|
+ categoryAttributeFilters(slug: $slug, filter: $filter) {
|
|
|
+ edges {
|
|
|
+ node {
|
|
|
+ _id
|
|
|
+ code
|
|
|
+ adminName
|
|
|
+ type
|
|
|
+ swatchType
|
|
|
+ position
|
|
|
+ minPrice
|
|
|
+ maxPrice
|
|
|
+ options {
|
|
|
+ edges {
|
|
|
+ node {
|
|
|
+ _id
|
|
|
+ adminName
|
|
|
+ sortOrder
|
|
|
+ swatchValue
|
|
|
+ productCount
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pageInfo {
|
|
|
+ hasNextPage
|
|
|
+ endCursor
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+变量:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "slug": "ready-to-go-wig",
|
|
|
+ "filter": "{\"wig_color\":{\"match\":\"33\"},\"price_from\":10,\"price_to\":212}"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 返回示例
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "data": {
|
|
|
+ "categoryAttributeFilters": {
|
|
|
+ "edges": [
|
|
|
+ {
|
|
|
+ "node": {
|
|
|
+ "_id": 10,
|
|
|
+ "code": "price",
|
|
|
+ "adminName": "Price",
|
|
|
+ "type": "price",
|
|
|
+ "swatchType": null,
|
|
|
+ "position": 1,
|
|
|
+ "minPrice": 10,
|
|
|
+ "maxPrice": 212,
|
|
|
+ "options": { "edges": [] }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "node": {
|
|
|
+ "_id": 23,
|
|
|
+ "code": "wig_color",
|
|
|
+ "adminName": "Wig Color",
|
|
|
+ "type": "select",
|
|
|
+ "swatchType": "color",
|
|
|
+ "position": 2,
|
|
|
+ "minPrice": 0,
|
|
|
+ "maxPrice": 0,
|
|
|
+ "options": {
|
|
|
+ "edges": [
|
|
|
+ {
|
|
|
+ "node": {
|
|
|
+ "_id": 33,
|
|
|
+ "adminName": "Blonde",
|
|
|
+ "sortOrder": 1,
|
|
|
+ "swatchValue": "#F5DEB3",
|
|
|
+ "productCount": 12
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "pageInfo": {
|
|
|
+ "hasNextPage": false,
|
|
|
+ "endCursor": null
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 注意事项
|
|
|
+
|
|
|
+1. **可筛选属性来源**:接口基于分类下产品的实际属性值动态推导(`is_filterable=1` 且产品在该分类下使用了该属性),而非后台 `category_filterable_attributes` 配置表。
|
|
|
+2. **price 属性始终存在**:即使后台未配置,也会自动补充,`minPrice`/`maxPrice` 从产品价格索引计算。
|
|
|
+3. **性能**:每个选项的 `productCount` 通过 SQL 聚合计算,属性/选项较多时建议配合缓存。
|