## ADDED Requirements

### Requirement: IoT 卡虚拟号字段

系统 SHALL 在 `tb_iot_card` 表新增 `virtual_no` 字段，与设备的虚拟号概念对等，供客服和客户通过统一虚拟号查找资产。

**字段定义**:
- 字段名：`virtual_no`（VARCHAR(50)，可空）
- 全局唯一索引：`CREATE UNIQUE INDEX idx_iot_card_virtual_no ON tb_iot_card (virtual_no) WHERE deleted_at IS NULL`
- 老数据：`virtual_no` 为 NULL（已有卡不强制要求有虚拟号）
- 允许手动修改

**唯一性规则**:
- 在所有未软删除的卡中唯一（部分索引，deleted_at IS NULL）
- 导入时与数据库现存数据重复则整批失败，响应中包含冲突的具体 virtual_no 列表

**虚拟号的使用场景**:
- resolve 接口：支持通过 virtual_no 查找卡
- 客服工单：客服将虚拟号告知客户，客户通过虚拟号自助查询

#### Scenario: 为卡设置唯一虚拟号

- **WHEN** 管理员为 ICCID 为 "898601234..." 的卡设置 virtual_no = "CARD-001"
- **THEN** 系统保存成功，`idx_iot_card_virtual_no` 确保全局唯一

#### Scenario: 导入批次中有重复虚拟号

- **WHEN** ICCID 导入批次中，有 1 条记录的 virtual_no 与数据库现存卡的 virtual_no 重复
- **THEN** 系统拒绝整批导入，响应中返回冲突的 virtual_no 及所属行号

#### Scenario: virtual_no 为空的老卡

- **WHEN** 系统中有历史导入的卡，没有 virtual_no
- **THEN** 这些卡的 virtual_no = NULL，不影响唯一索引（部分索引跳过 NULL 值）
