## Why

上游 IoT 平台返回的 ICCID 格式不固定（部分运营商 19 位为唯一标识，部分运营商需要完整 20 位才能唯一标识一张卡），而当前 `tb_iot_card.iccid` 仅支持精确匹配查询。当上游传入的位数与数据库存储的位数不一致时，查询静默失败（返回空结果但不报错），导致设备当前使用卡的 `is_current` 状态更新失效，产生不可观测的数据错乱。

## What Changes

- 在 `tb_iot_card` 表新增 `iccid_19`（varchar(19)）和 `iccid_20`（varchar(20)）两列，分别存储 ICCID 的前 19 位和完整 20 位（19 位卡的 `iccid_20` 为 NULL）
- 在 `tb_personal_customer_iccid` 表新增 `iccid_19` 列，采用相同策略
- 所有 ICCID 精确查询改为**按上游传入长度路由**：19 位查 `iccid_19`，20 位查 `iccid_20`，Miss 时记录告警而非降级
- 不降级、不跨列匹配——上游数据质量问题在日志层暴露，不在查询层消化

## Capabilities

### New Capabilities

（无新增业务能力）

### Modified Capabilities

- `iot-card`：`tb_iot_card` 存储结构变更，新增两列及对应索引；IotCardStore 的所有精确查询方法（GetByICCID、GetByICCIDs、ExistsByICCID、ExistsByICCIDBatch）改用新列路由
- `iot-card-import-task`：导入任务在写入 IotCard 时同步填充 `iccid_19` / `iccid_20` 两列

## Impact

**数据库**
- `tb_iot_card`：新增 `iccid_19`、`iccid_20` 两列 + Partial Index（过滤软删除）
- `tb_personal_customer_iccid`：新增 `iccid_19` 列 + 索引
- 存量数据一次性回填脚本（迁移文件中执行）

**Store 层**（共 3 个文件，~10 个方法）
- `iot_card_store.go`：GetByICCID、GetByICCIDs、ExistsByICCID、ExistsByICCIDBatch
- `personal_customer_iccid_store.go`：GetByICCID、GetByCustomerAndICCID
- `device_sim_binding_store.go`：UpdateIsCurrentByDeviceID（内部子查询）、GetBoundICCIDs

**Service 层**（1 处内联 SQL）
- `enterprise_card/service.go`：`WHERE iccid IN ?` 直接 SQL 改为调用 Store 方法或适配新列

**Task 层**（1 处写入路径）
- `iot_card_import.go`：processBatch() 中 IotCard 初始化时赋值新字段
