## 1. 数据库迁移

- [x] 1.1 新建迁移文件 `migrations/000110_add_device_virtual_no_to_iot_card.up.sql`，添加 `device_virtual_no VARCHAR(100) NOT NULL DEFAULT ''` 列，并附回填 SQL（JOIN `tb_device_sim_binding` + `tb_device` 更新现有绑定数据）
- [x] 1.2 新建对应 down 文件 `migrations/000110_add_device_virtual_no_to_iot_card.down.sql`，执行 `DROP COLUMN device_virtual_no`
- [x] 1.3 执行迁移：`make migrate-up`，确认列存在且回填数据正确

## 2. Model 层

- [x] 2.1 在 `internal/model/iot_card.go` 的 `IotCard` 结构体新增字段 `DeviceVirtualNo string`，添加正确的 GORM tag 和中文注释

## 3. Store 层

- [x] 3.1 在 `internal/store/postgres/iot_card_store.go` 的 `ListStandalone` 方法中，将硬编码的 `WHERE is_standalone = true` 改为：仅当 filters["is_standalone"] 非 nil 时才拼接该条件
- [x] 3.2 在 `IotCardStore` 新增方法 `UpdateDeviceVirtualNo(ctx, cardID uint, deviceVirtualNo string) error`，使用 GORM `Updates` 单卡更新
- [x] 3.3 在 `IotCardStore` 新增方法 `BatchUpdateDeviceVirtualNo(ctx, cardIDs []uint, deviceVirtualNo string) error`，使用 GORM `WHERE id IN (?)` 批量更新

## 4. DTO 层

- [x] 4.1 在 `internal/model/dto/iot_card_dto.go` 的 `ListStandaloneIotCardRequest` 中：删除 `VirtualNo` 字段，新增 `IsStandalone *bool` 字段（含 query tag 和 description）
- [x] 4.2 在 `StandaloneIotCardResponse` 中新增 `DeviceVirtualNo string` 字段（含 json tag 和 description）

## 5. Service 层 - IoT 卡列表

- [x] 5.1 在 `internal/service/iot_card/service.go` 的 `ListStandalone` 方法中：删除对 `req.VirtualNo` 的处理，改为读取 `req.IsStandalone` 并写入 `filters["is_standalone"]`
- [x] 5.2 在 `toStandaloneResponse` 方法中新增 `DeviceVirtualNo: card.DeviceVirtualNo` 字段赋值

## 6. Service 层 - 绑定/解绑快照

- [x] 6.1 在 `internal/service/device/binding.go` 的 `BindCard` 方法中，绑定记录创建成功后，调用 `s.iotCardStore.UpdateDeviceVirtualNo(ctx, card.ID, device.VirtualNo)`；失败仅记录 warn 日志，不阻断主流程
- [x] 6.2 在 `internal/service/device/binding.go` 的 `UnbindCard` 方法中，解绑成功后，调用 `s.iotCardStore.UpdateDeviceVirtualNo(ctx, cardID, "")`；失败仅记录 warn 日志，不阻断主流程

## 7. Task 层 - 设备导入快照

- [x] 7.1 在 `internal/task/device_import.go` 的事务块内，创建绑定记录后，收集所有 `validCardIDs`，调用 `h.iotCardStore.BatchUpdateDeviceVirtualNo(ctx, validCardIDs, device.VirtualNo)`（在同一事务中执行）

## 8. 构建验证

- [x] 8.1 运行 `go build ./...` 确认无编译错误
- [x] 8.2 运行 `bash scripts/check-all.sh` 确认无规范违规（check 失败项为已有历史问题，本次变更未引入新违规）
