## api_v2：按流程节点查询 PlateOrder 列表（含该节点工艺参数 key/value）

### 目标
- **给前端提供**：按指定 `process_node_id` 拉取“当前处于该流程节点”的 `PlateOrder` 列表。
- **同时返回**：
  - 该节点（`State`）关联的工艺参数**模板默认值**（key/value）
  - **每个订单在该节点上的参数值**（key/value，订单维度；若从未提交则为 null）

### “处于该节点”的判定语义（与 stateflow 现有实现保持一致）
- 本接口采用 **NEXT 语义**：`process_node` 对应的 `state` 是该 `PlateOrder.business_object` 的 **下一个待执行节点**。
- 等价规则（忽略已撤销记录 `is_cancelled=True`）：
  - 该节点之前（同一 `process`、`order` 更小）的所有节点均已完成（存在未撤销的 `StateFlowRecord`）
  - 该节点本身尚未完成（不存在未撤销的 `StateFlowRecord`）
- 仅查询满足以下条件的订单：
  - `PlateOrder.business_object` 存在
  - `PlateOrder.business_object.process_id == process_node.process_id`

### 接口信息
- **Method**：GET
- **Path**：`/api/v2/plate-orders/by-process-node/`
- **认证**：JWT（`IsAuthenticated`）
- **权限**：仅允许印染/工厂侧用户（与 v2 printing 其它接口一致，`IsPrintingFactory`）

### Query 参数
| 参数 | 必填 | 类型 | 默认值 | 说明 |
|---|---:|---|---|---|
| `process_node_id` | 是 | int | - | `stateflow.ProcessNode.id` |
| `search` | 否 | string | - | 单一搜索参数：同时支持主键与设计编号（见“查询规则”） |
| `ordering` | 否 | string | `-created_at` | 排序字段（见“排序规则”） |
| `limit` | 否 | int | `20` | 分页大小（LimitOffsetPagination） |
| `offset` | 否 | int | `0` | 分页偏移（LimitOffsetPagination） |

### 查询规则（search）
- 当 `search` 为**纯数字**：
  - 匹配 `PlateOrder.id == int(search)` **或**
  - 匹配 `PlateOrder.design_code icontains search`
- 当 `search` 为**非纯数字**：
  - 仅匹配 `PlateOrder.design_code icontains search`

### 排序规则（ordering）
- 默认：`-created_at`
- 支持字段：`id` / `created_at` / `updated_at` / `design_code`
- `design_code` 排序规则：
  - 当 `design_code` 为空时，使用 `id` 的字符串作为兜底值参与排序（保证排序稳定、可预测）
- 传入不支持的 `ordering`：返回 **400**

### 返回值（200）
响应为分页结构，并额外附带节点信息与该节点工艺参数 key/value。

#### 顶层字段
| 字段 | 类型 | 说明 |
|---|---|---|
| `process_node` | object | 目标流程节点信息（见下） |
| `parameters` | array[object] | 该节点 `State.parameters` 的 key/value（**模板默认值**；不是订单提交值） |
| `count` | int | 满足条件的总数 |
| `next` | string\|null | 下一页链接 |
| `previous` | string\|null | 上一页链接 |
| `results` | array[object] | 当前页的 `PlateOrder` 列表（见下） |

#### `process_node` 字段
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | int | `ProcessNode.id` |
| `process_id` | int | `Process.id` |
| `state_id` | int | `State.id` |
| `state_name` | string | `State.name` |
| `order` | int | 节点顺序号 |

#### `parameters` 元素字段（仅 key/value）
| 字段 | 类型 | 说明 |
|---|---|---|
| `key` | string | 参数键 |
| `value` | string\|null | 参数默认值（如有） |

#### `process_parameters` 元素字段（订单维度：严格 schema）
> 该字段存在于 `results[*].process_parameters`，用于“每个订单在当前节点上的参数值”展示/回显。

| 字段 | 类型 | 说明 |
|---|---|---|
| `key` | string | 参数键；**与顶层 `parameters[*].key` 一致** |
| `value` | JSONValue\|null | 该订单在此节点的最新已提交参数值；若从未提交过该节点参数，则为 null |

**JSONValue 定义**（用于前端类型定义）：
- `string` \| `number` \| `boolean` \| `object` \| `array` \| `null`

**不变性约束（前端可依赖）**：
- 对任意返回的 `PlateOrder`：
  - `process_parameters` **一定存在**，类型恒为 `array`
  - `process_parameters` 的 **key 集合与顺序**与顶层 `parameters` **完全一致**
  - 若该节点无任何参数：`parameters=[]` 且 `process_parameters=[]`

**取值规则（value 来源）**：
- 取该订单 `business_object` 在目标 `state` 的**最新一条** `StateFlowRecord`（按 `completed_at` 倒序，`id` 倒序）关联的参数提交汇总；同一条状态日志下多次补充参数时，后提交覆盖先提交。
- 若该节点当前为“待执行”（NEXT），通常不会有未撤销的完成日志；当订单曾完成过该节点但后续回退时，会存在已撤销的日志，此时仍可能带有历史参数值用于回显。

#### `results` 元素字段（PlateOrder 列表项）
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | int | PlateOrder 主键 |
| `design_code` | string\|null | 设计编号；若为空则返回 `id` 的字符串兜底值 |
| `customer` | int | 客户 ID |
| `customer_name` | string | 客户名称 |
| `style_name` | string\|null | 款号名称 |
| `urgency_level` | string | 紧急程度 |
| `is_invalid` | bool | 是否作废 |
| `business_object_id` | int\|null | 关联流程实例 ID |
| `process_parameters` | array[object] | **订单维度**的该节点参数 key/value（与顶层 `parameters` 的 key 集合一致；若该订单从未提交过该节点参数，则对应 value 为 null） |
| `created_at` | string | 创建时间（ISO 8601） |
| `updated_at` | string | 更新时间（ISO 8601） |

### 常见错误码
| HTTP 状态码 | 场景 | 返回 `detail` |
|---:|---|---|
| 400 | 缺少/非法参数（如 `process_node_id` 非数字、`ordering` 不支持） | 错误原因文本 |
| 401 | 未认证（缺少/无效 JWT） | DRF 默认 |
| 403 | 已认证但无权限（非工厂用户） | `您没有访问印染订单的权限` |
| 404 | `process_node_id` 不存在 | `process_node 不存在` |


