All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m3s
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
9.4 KiB
9.4 KiB
1. 数据库迁移(先行)
- 1.1 创建迁移文件:
tb_device.device_no→virtual_no,tb_personal_customer_device.device_no→virtual_no(两张表在同一个迁移文件中完成) - 1.2 创建迁移文件:
tb_iot_card新增virtual_no VARCHAR(50)字段,创建部分唯一索引idx_iot_card_virtual_no(WHERE deleted_at IS NULL) - 1.3 创建迁移文件:
tb_package新增virtual_ratio DECIMAL(10,6) DEFAULT 1.0字段,回填现有数据(根据enable_virtual_data和real_data_mb / virtual_data_mb计算) - 1.4 执行全部迁移,验证三张表结构变更成功(PostgreSQL MCP 确认)
2. 数据模型更新(device_no 全量改名)
- 2.1 更新
internal/model/device.go:DeviceNo→VirtualNo,GORM column tag 从device_no改为virtual_no,更新注释 - 2.2 更新
internal/model/personal_customer_device.go:DeviceNo→VirtualNo,column tag 同步更新 - 2.3 更新
internal/model/dto/device_dto.go:DeviceResponse.DeviceNo→VirtualNo,JSON tag 从"device_no"改为"virtual_no";ListDeviceRequest.DeviceNo→VirtualNo,query tag 同步更新;AllocationDeviceFailedItem.DeviceNo→VirtualNo;DeviceSeriesBindngFailedItem.DeviceNo→VirtualNo - 2.4 全量搜索代码中所有
.DeviceNo引用(Store/Service/Handler 层),逐一替换为.VirtualNo(使用 lsp_rename 保证全量覆盖) - 2.5 运行
go build ./...确认无编译错误,运行lsp_diagnostics确认无类型错误
3. IotCard 模型更新(新增 virtual_no 字段)
- 3.1 更新
internal/model/iot_card.go:新增VirtualNo string字段,GORM tag 包含column:virtual_no; type:varchar(50); uniqueIndex:idx_iot_card_virtual_no,where:deleted_at IS NULL注释 - 3.2 运行
lsp_diagnostics确认模型字段无错误
4. Package 模型更新(新增 virtual_ratio 字段)
- 4.1 更新
internal/model/package.go:Package结构体新增VirtualRatio float64字段,GORM tagcolumn:virtual_ratio; type:decimal(10,6); default:1.0 - 4.2 更新
internal/service/package/service.go:在套餐创建和更新逻辑中自动计算并存储virtual_ratio(enable_virtual_data=true且virtual_data_mb>0时 =real_data_mb/virtual_data_mb,否则 = 1.0) - 4.3 运行
lsp_diagnostics确认无错误
5. Redis 常量新增
- 5.1 在
pkg/constants/redis.go新增RedisDeviceProtectKey(deviceID uint, action string) string(格式:protect:device:{id}:{action},TTL 注释:1 小时) - 5.2 在
pkg/constants/redis.go新增RedisDeviceRefreshCooldownKey(deviceID uint) string(格式:refresh:cooldown:device:{id},TTL 注释:冷却时长,建议 30 秒) - 5.3 在
pkg/constants/redis.go新增RedisPollingQueueProtectKey() string(格式:polling:queue:protect) - 5.4 在
pkg/constants/新增设备保护期时长常量DeviceProtectPeriodDuration = 1 * time.Hour,设备刷新冷却时长常量DeviceRefreshCooldownDuration = 30 * time.Second
6. RefreshCardDataFromGateway 方法增强
- 6.1 在
internal/service/iot_card/service.go中将SyncCardStatusFromGateway改名为RefreshCardDataFromGateway - 6.2 增强方法实现:调用网关查询卡状态(网络状态)、实名状态、本月流量用量,将结果写回 DB:更新
network_status、real_name_status、current_month_usage_mb、last_sync_time(参考 polling_handler.go 中的完整同步逻辑) - 6.3 更新所有调用
SyncCardStatusFromGateway的地方改为RefreshCardDataFromGateway(全局搜索替换) - 6.4 运行
go build ./...确认无编译错误
7. 新建 AssetService
- 7.1 创建
internal/service/asset/service.go,定义Service结构体,依赖注入:DeviceStore、IotCardStore、PackageUsageStore、PackageStore、Redis(通过现有 bootstrap 体系接入) - 7.2 实现
Resolve(ctx, identifier string) (*dto.AssetResolveResponse, error):先查设备(virtual_no/imei/sn),再查卡(virtual_no/iccid/msisdn),应用数据权限过滤,聚合套餐流量(含 virtual_ratio 换算)、保护期状态、绑定信息 - 7.3 实现
GetRealtimeStatus(ctx, assetType string, id uint) (*dto.AssetRealtimeStatusResponse, error):仅读 DB/Redis 持久化数据,不调网关;card 返回网络状态/实名/流量/最后同步;device 返回保护期状态+所有绑定卡状态 - 7.4 实现
Refresh(ctx, assetType string, id uint) (*dto.AssetRealtimeStatusResponse, error):card 调RefreshCardDataFromGateway;device 检查 Redis 冷却期(429),可刷新则遍历绑定卡调RefreshCardDataFromGateway,设置冷却 Key - 7.5 实现
GetPackages(ctx, assetType string, id uint) ([]*dto.AssetPackageResponse, error):按 asset_type 查 PackageUsage(card→iot_card_id,device→device_id),全量返回按创建时间倒序,含 virtual_ratio 展示换算 - 7.6 实现
GetCurrentPackage(ctx, assetType string, id uint) (*dto.AssetPackageResponse, error):查 status=1 且 master_usage_id IS NULL 的主套餐,无则返回 ErrNotFound
8. 设备停复机 Service
- 8.1 在
internal/service/device/service.go实现StopDevice(ctx, deviceID uint) (*dto.DeviceSuspendResponse, error):验证设备存在、检查保护期、获取已实名绑定卡、批量调网关停机、更新卡状态、设置 Redis stop 保护期(部分失败时仍设置) - 8.2 实现
StartDevice(ctx, deviceID uint) error:验证设备存在、检查保护期、获取已实名绑定卡、批量调网关复机、更新卡状态、设置 Redis start 保护期
9. 卡停复机 Service 扩展
- 9.1 在
internal/service/iot_card/stop_resume_service.go实现ManualStopCard(ctx, iccid string) error:通过 ICCID 查卡、验证已实名、检查绑定设备的保护期(stop 保护期允许、start 保护期允许)、调网关停机、更新卡状态 - 9.2 实现
ManualStartCard(ctx, iccid string) error:通过 ICCID 查卡、验证已实名、检查绑定设备的保护期(stop 保护期→拒绝 403、start 保护期→允许)、调网关复机、更新卡状态
10. DTO 新增
- 10.1 在
internal/model/dto/新增asset_dto.go,定义以下 DTO(含所有字段及 description tag):AssetResolveResponse、BoundCardInfo、AssetRealtimeStatusResponse、AssetPackageResponse
- 10.2
DeviceSuspendResponse(成功信息 + 失败卡列表,已在 device_dto.go 中)
11. 新建 AssetHandler 和路由注册
- 11.1 创建
internal/handler/admin/asset.go,定义AssetHandler结构体和 9 个 Handler 方法(Resolve、RealtimeStatus、Refresh、Packages、CurrentPackage、StopDevice、StartDevice、StopCard、StartCard) - 11.2 创建
internal/routes/asset.go注册/api/admin/assets/*路由(9 个端点);企业账号访问 resolve 时在 Handler 层检查 user_type 返回 403 - 11.3 更新
internal/bootstrap/types.go、services.go、handlers.go,将 Asset、StopResumeService 加入 bootstrap 体系;更新 docs 文件
12. 轮询系统新增保护期一致性检查任务
- 12.1
RedisPollingQueueProtectKey()已存在(Task 5.3) - 12.2 在
internal/task/polling_handler.go新增HandleProtectConsistencyCheck:检查 is_standalone、real_name_status、设备保护期 Redis Key,按规则强制同步网络状态 - 12.3 在
pkg/constants/constants.go添加TaskTypePollingProtect,在pkg/queue/handler.go注册处理器
13. 卡 ICCID 导入支持 virtual_no 列
- 13.1
pkg/utils/excel.go新增 virtual_no 列识别(关键字:virtual_no/VirtualNo/虚拟号/设备号) - 13.2
internal/task/iot_card_import.go实现 virtual_no 唯一性校验和写入逻辑;IotCardStore新增ExistsByVirtualNoBatch
14. 删除废弃接口
14a. 废弃停复机接口
- 14.1 删除
internal/handler/admin/enterprise_card.go中的SuspendCard和ResumeCardHandler - 14.2 删除
internal/handler/h5/enterprise_device.go中的SuspendCard和ResumeCardHandler - 14.3 删除
internal/handler/admin/iot_card.go中的StopCard和StartCardHandler - 14.4 清理对应路由注册,
go build ./...通过
14b. 废弃详情查询和网关直查接口
- 14.5 删除
internal/handler/admin/iot_card.go中的GetByICCIDHandler - 14.6 删除
internal/handler/admin/iot_card.go中的GetGatewayStatus、GetGatewayFlow、GetGatewayRealname三个 Handler - 14.7 删除
internal/handler/admin/device.go中的GetByIDHandler - 14.8 删除
internal/handler/admin/device.go中的GetByIdentifierHandler - 14.9 删除
internal/handler/admin/device.go中的GetGatewayInfoHandler - 14.10 清理对应路由注册,
go build ./...通过
15. 文档和最终验收
- 15.1 更新 API 文档生成器,运行
go run cmd/gendocs/main.go确认 9 个新接口出现在文档中 - 15.2 使用 PostgreSQL MCP 验证三张表结构变更正确(tb_device.virtual_no 唯一索引、tb_iot_card.virtual_no 条件唯一索引、tb_package.virtual_ratio 字段 NOT NULL DEFAULT 1.0)
- 15.3 使用 PostgreSQL MCP 验证 Package 数据回填正确(enable_virtual_data=true 的套餐 virtual_ratio=930.9,非 1.0)
- 15.4 运行
go build ./...全量检查无编译错误 - 15.5 tasks.md 全部任务标记完成