feat: 新增数据库迁移,重命名 device_no 为 virtual_no,新增 iot_card.virtual_no 和 package.virtual_ratio 字段
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>
This commit is contained in:
2026-03-14 18:27:28 +08:00
parent b5147d1acb
commit b9c3875c08
77 changed files with 5832 additions and 2393 deletions

View File

@@ -48,7 +48,7 @@ func (s *DeviceStore) GetByID(ctx context.Context, id uint) (*model.Device, erro
func (s *DeviceStore) GetByDeviceNo(ctx context.Context, deviceNo string) (*model.Device, error) {
var device model.Device
query := s.db.WithContext(ctx).Where("device_no = ?", deviceNo)
query := s.db.WithContext(ctx).Where("virtual_no = ?", deviceNo)
// 应用数据权限过滤NULL shop_id 对代理用户不可见)
query = middleware.ApplyShopFilter(ctx, query)
if err := query.First(&device).Error; err != nil {
@@ -58,10 +58,10 @@ func (s *DeviceStore) GetByDeviceNo(ctx context.Context, deviceNo string) (*mode
}
// GetByIdentifier 通过任意标识符查找设备
// 支持 device_no虚拟号、imei、sn 三个字段的自动匹配
// 支持 virtual_no虚拟号、imei、sn 三个字段的自动匹配
func (s *DeviceStore) GetByIdentifier(ctx context.Context, identifier string) (*model.Device, error) {
var device model.Device
query := s.db.WithContext(ctx).Where("device_no = ? OR imei = ? OR sn = ?", identifier, identifier, identifier)
query := s.db.WithContext(ctx).Where("virtual_no = ? OR imei = ? OR sn = ?", identifier, identifier, identifier)
// 应用数据权限过滤NULL shop_id 对代理用户不可见)
query = middleware.ApplyShopFilter(ctx, query)
if err := query.First(&device).Error; err != nil {
@@ -100,8 +100,8 @@ func (s *DeviceStore) List(ctx context.Context, opts *store.QueryOptions, filter
// 应用数据权限过滤NULL shop_id 对代理用户不可见)
query = middleware.ApplyShopFilter(ctx, query)
if deviceNo, ok := filters["device_no"].(string); ok && deviceNo != "" {
query = query.Where("device_no LIKE ?", "%"+deviceNo+"%")
if virtualNo, ok := filters["virtual_no"].(string); ok && virtualNo != "" {
query = query.Where("virtual_no LIKE ?", "%"+virtualNo+"%")
}
if deviceName, ok := filters["device_name"].(string); ok && deviceName != "" {
query = query.Where("device_name LIKE ?", "%"+deviceName+"%")
@@ -184,17 +184,17 @@ func (s *DeviceStore) ExistsByDeviceNoBatch(ctx context.Context, deviceNos []str
}
var existingDevices []struct {
DeviceNo string
VirtualNo string
}
if err := s.db.WithContext(ctx).Model(&model.Device{}).
Select("device_no").
Where("device_no IN ?", deviceNos).
Select("virtual_no").
Where("virtual_no IN ?", deviceNos).
Find(&existingDevices).Error; err != nil {
return nil, err
}
for _, d := range existingDevices {
result[d.DeviceNo] = true
result[d.VirtualNo] = true
}
return result, nil
}
@@ -204,7 +204,7 @@ func (s *DeviceStore) GetByDeviceNos(ctx context.Context, deviceNos []string) ([
if len(deviceNos) == 0 {
return devices, nil
}
query := s.db.WithContext(ctx).Where("device_no IN ?", deviceNos)
query := s.db.WithContext(ctx).Where("virtual_no IN ?", deviceNos)
// 应用数据权限过滤NULL shop_id 对代理用户不可见)
query = middleware.ApplyShopFilter(ctx, query)
if err := query.Find(&devices).Error; err != nil {