## ADDED Requirements

### Requirement: Device Batch Series Binding Selection Contract

The system SHALL expose `PATCH /api/admin/devices/series-binding` using a batch target-selection contract consistent with other batch asset operations.

The request MUST include `series_id`. The request MAY omit `selection_type` only for backward compatibility, and in that case the system MUST treat the request as `selection_type=list`.

When `selection_type=list`, the request MUST use `device_ids` to identify the target devices and MUST support up to 1000 device IDs.

When `selection_type=range`, the request MUST use `virtual_no_start` and `virtual_no_end` to identify the target device range.

When `selection_type=filter`, the request MUST support selecting the full filtered result set by the same device query dimensions used for batch operations, including `virtual_no`, `device_name`, `device_type`, `manufacturer`, `batch_no`, `status`, `shop_id`, `shop_ids`, `filter_series_id`, `created_at_start`, and `created_at_end`.

`series_id=0` MUST mean clearing the current series binding instead of binding a new series.

#### Scenario: Bind device series by explicit device ID list

- **GIVEN** 用户已经明确选中了多台设备
- **WHEN** 系统调用 `PATCH /api/admin/devices/series-binding`
- **AND** 请求体包含 `selection_type="list"`、`series_id=12`、`device_ids=[1001,1002,1003]`
- **THEN** 系统 MUST 按 `device_ids` 对这批设备设置目标套餐系列绑定

#### Scenario: Bind device series by virtual number range

- **GIVEN** 用户希望按设备虚拟号区间批量设置套餐系列
- **WHEN** 系统调用 `PATCH /api/admin/devices/series-binding`
- **AND** 请求体包含 `selection_type="range"`、`series_id=12`、`virtual_no_start="V000001"`、`virtual_no_end="V000100"`
- **THEN** 系统 MUST 按虚拟号范围选出目标设备并设置套餐系列绑定

#### Scenario: Clear device series binding by filter result set

- **GIVEN** 用户希望对满足筛选条件的全部设备清除当前套餐系列关联
- **WHEN** 系统调用 `PATCH /api/admin/devices/series-binding`
- **AND** 请求体包含 `selection_type="filter"`、`series_id=0`、`status=1`、`shop_ids=[1,2]`
- **THEN** 系统 MUST 对完整筛选结果集执行清除操作
- **AND** 系统 MUST NOT 只处理当前分页内已渲染的设备

#### Scenario: Omitted selection type remains compatible with legacy callers

- **GIVEN** 旧版调用方只提交 `device_ids` 和 `series_id`
- **WHEN** 系统调用 `PATCH /api/admin/devices/series-binding`
- **AND** 请求体包含 `device_ids=[1001,1002]`、`series_id=8`
- **THEN** 系统 MUST 将该请求视为 `selection_type="list"`
- **AND** 系统 MUST 继续按 `device_ids` 处理目标设备

### Requirement: Device Batch Series Binding Shop Filter Selector

The system SHALL use the cascade shop query endpoint for the shop selector in device batch series binding filter mode.

When the user filters devices by shop in the batch series binding dialog, the UI MUST load shop options from `GET /api/admin/shops/cascade` with `exclude_self=true`, present them as a cascade selector, and submit the last selected node as `shop_id`.

#### Scenario: Shop filter uses cascade endpoint with self excluded

- **GIVEN** 用户打开“批量设置设备套餐系列绑定”弹窗
- **AND** 用户选择 `selection_type="filter"`
- **WHEN** 用户展开“店铺名称”选择器
- **THEN** 系统 MUST 调用 `GET /api/admin/shops/cascade`
- **AND** 请求参数 MUST 包含 `exclude_self=true`
- **AND** 系统 MUST 按级联树结构展示可选店铺

#### Scenario: Shop cascade selection submits the last selected node

- **GIVEN** 用户在“店铺名称”级联选择器中依次选择某条店铺路径
- **WHEN** 用户确认提交设备批量套餐系列绑定
- **THEN** 系统 MUST 取该路径最后一级节点的 ID 作为请求中的 `shop_id`

### Requirement: Device Batch Series Binding Result Summary

The system SHALL return a batch processing summary for device series binding requests.

The result data MUST include `success_count`, `fail_count`, and `failed_items`. Each entry in `failed_items` MUST include `device_id`, `virtual_no`, and `reason`.

#### Scenario: Partial device binding failure returns itemized reasons

- **GIVEN** 某次设备批量套餐系列绑定同时存在成功项和失败项
- **WHEN** 接口返回处理结果
- **THEN** 响应数据 MUST 包含成功数量和失败数量
- **AND** 每条失败明细 MUST 返回对应的 `device_id`
- **AND** 每条失败明细 MUST 返回对应的 `virtual_no`
- **AND** 每条失败明细 MUST 返回可展示的失败原因 `reason`
