feat(设备列表): 新增 has_active_package 查询条件

- DTO ListDeviceRequest 增加 HasActivePackage *bool 字段(query/json: has_active_package)
- Service List 方法将 HasActivePackage 透传至 filters["has_active_package"]
- Store applyDeviceFilters 新增 applyHasActivePackageFilter:
  true  → EXISTS 子查询(生效中主套餐)
  false → NOT EXISTS 子查询
  均限制 master_usage_id IS NULL、deleted_at IS NULL,状态使用 constants.PackageUsageStatusActive

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 12:04:23 +08:00
parent ca939ff617
commit 5e7e68cce7
3 changed files with 24 additions and 2 deletions

View File

@@ -15,8 +15,9 @@ type ListDeviceRequest struct {
BatchNo string `json:"batch_no" query:"batch_no" validate:"omitempty,max=100" maxLength:"100" description:"批次号"`
DeviceType string `json:"device_type" query:"device_type" validate:"omitempty,max=50" maxLength:"50" description:"设备类型"`
Manufacturer string `json:"manufacturer" query:"manufacturer" validate:"omitempty,max=255" maxLength:"255" description:"制造商(模糊查询)"`
CreatedAtStart *time.Time `json:"created_at_start" query:"created_at_start" description:"创建时间起始"`
CreatedAtEnd *time.Time `json:"created_at_end" query:"created_at_end" description:"创建时间结束"`
CreatedAtStart *time.Time `json:"created_at_start" query:"created_at_start" description:"创建时间起始"`
CreatedAtEnd *time.Time `json:"created_at_end" query:"created_at_end" description:"创建时间结束"`
HasActivePackage *bool `json:"has_active_package" query:"has_active_package" description:"是否有生效中的套餐true:有生效中主套餐, false:无生效中主套餐)"`
}
type DeviceResponse struct {

View File

@@ -124,6 +124,9 @@ func (s *Service) List(ctx context.Context, req *dto.ListDeviceRequest) (*dto.Li
if req.SeriesID != nil {
filters["series_id"] = *req.SeriesID
}
if req.HasActivePackage != nil {
filters["has_active_package"] = *req.HasActivePackage
}
devices, total, err := s.deviceStore.List(ctx, opts, filters)
if err != nil {

View File

@@ -177,9 +177,27 @@ func (s *DeviceStore) applyDeviceFilters(query *gorm.DB, filters map[string]any)
if seriesID, ok := filters["series_id"].(uint); ok && seriesID > 0 {
query = query.Where("series_id = ?", seriesID)
}
if hasActive, ok := filters["has_active_package"].(bool); ok {
query = s.applyHasActivePackageFilter(query, hasActive)
}
return query
}
// applyHasActivePackageFilter 按"是否有生效中主套餐"过滤设备。
// true: 设备在 tb_package_usage 中存在生效中(status=PackageUsageStatusActive)的主套餐记录;
// false: 不存在上述记录。
func (s *DeviceStore) applyHasActivePackageFilter(query *gorm.DB, hasActive bool) *gorm.DB {
subQuery := `SELECT 1 FROM tb_package_usage AS pu
WHERE pu.device_id = tb_device.id
AND pu.status = ?
AND pu.master_usage_id IS NULL
AND pu.deleted_at IS NULL`
if hasActive {
return query.Where("EXISTS ("+subQuery+")", constants.PackageUsageStatusActive)
}
return query.Where("NOT EXISTS ("+subQuery+")", constants.PackageUsageStatusActive)
}
func (s *DeviceStore) applyActivationStatusFilter(query *gorm.DB, activationStatus int) *gorm.DB {
activeCondition := `EXISTS (
SELECT 1