All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m35s
- 新增不轮询清单 tb_card_polling_pause(迁移 000256 补写存量),所有改 enable_polling 的入口同事务写清单 - 卡、设备勾选批量开关轮询(单次 500,逐项结果,开启跳过风险停机与已销户)与 CSV 文件导入 - 订单套餐生效、改有效期后自动恢复轮询并按规则评估复机 - 不轮询清单查询与导出;卡、设备列表与导出增加是否轮询 - 失败告警停机被拒视图、导出与批量关闭轮询;开关轮询影响说明 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
112 lines
3.5 KiB
Go
112 lines
3.5 KiB
Go
// Package pollingpause 是不轮询清单的只读查询,供后台列表与导出共用(add-polling-pause-list-and-batch-toggle)。
|
||
package pollingpause
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"gorm.io/gorm"
|
||
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
)
|
||
|
||
// Filter 是不轮询清单筛选条件。
|
||
type Filter struct {
|
||
AssetType string
|
||
CarrierID *uint
|
||
Source string
|
||
Status *int
|
||
Identifier string
|
||
OperatorID *uint
|
||
StartTime *time.Time
|
||
EndTime *time.Time
|
||
}
|
||
|
||
// Row 是清单记录与资产当前状态、名称的投影。
|
||
type Row struct {
|
||
model.CardPollingPause
|
||
CarrierName string
|
||
EnablePolling bool
|
||
GatewayExtend string
|
||
ClosedByName string
|
||
RestoredByName string
|
||
}
|
||
|
||
// EnsureAllowed 不轮询清单仅超级管理员与平台账号可查看与导出。
|
||
func EnsureAllowed(userType int) error {
|
||
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
|
||
return nil
|
||
}
|
||
return errors.New(errors.CodeForbidden, "仅平台账号可查看不轮询清单")
|
||
}
|
||
|
||
// Query 不轮询清单只读查询。
|
||
type Query struct {
|
||
db *gorm.DB
|
||
}
|
||
|
||
// NewQuery 创建不轮询清单查询。
|
||
func NewQuery(db *gorm.DB) *Query {
|
||
return &Query{db: db}
|
||
}
|
||
|
||
func (q *Query) base(ctx context.Context, filter Filter) *gorm.DB {
|
||
query := q.db.WithContext(ctx).Table("tb_card_polling_pause AS p")
|
||
if filter.AssetType != "" {
|
||
query = query.Where("p.asset_type = ?", filter.AssetType)
|
||
}
|
||
if filter.CarrierID != nil {
|
||
query = query.Where("p.carrier_id = ?", *filter.CarrierID)
|
||
}
|
||
if filter.Source != "" {
|
||
query = query.Where("p.close_source = ?", filter.Source)
|
||
}
|
||
if filter.Status != nil {
|
||
query = query.Where("p.status = ?", *filter.Status)
|
||
}
|
||
if filter.Identifier != "" {
|
||
query = query.Where("p.identifier = ?", filter.Identifier)
|
||
}
|
||
if filter.OperatorID != nil {
|
||
query = query.Where("p.closed_by = ?", *filter.OperatorID)
|
||
}
|
||
if filter.StartTime != nil {
|
||
query = query.Where("p.closed_at >= ?", *filter.StartTime)
|
||
}
|
||
if filter.EndTime != nil {
|
||
query = query.Where("p.closed_at <= ?", *filter.EndTime)
|
||
}
|
||
return query
|
||
}
|
||
|
||
// Count 统计符合条件的记录数。
|
||
func (q *Query) Count(ctx context.Context, filter Filter) (int64, error) {
|
||
var total int64
|
||
if err := q.base(ctx, filter).Count(&total).Error; err != nil {
|
||
return 0, errors.Wrap(errors.CodeDatabaseError, err, "统计不轮询清单失败")
|
||
}
|
||
return total, nil
|
||
}
|
||
|
||
// Page 按关闭时间倒序返回一页记录,附带资产当前轮询开关、网关扩展状态、运营商账户与操作人名称。
|
||
func (q *Query) Page(ctx context.Context, filter Filter, offset, limit int) ([]Row, error) {
|
||
var rows []Row
|
||
err := q.base(ctx, filter).
|
||
Select(`p.*, COALESCE(ca.carrier_name, '') AS carrier_name,
|
||
COALESCE(c.enable_polling, d.enable_polling, FALSE) AS enable_polling,
|
||
COALESCE(c.gateway_extend, '') AS gateway_extend,
|
||
COALESCE(a1.username, '') AS closed_by_name, COALESCE(a2.username, '') AS restored_by_name`).
|
||
Joins("LEFT JOIN tb_iot_card c ON p.asset_type = 'iot_card' AND c.id = p.asset_id").
|
||
Joins("LEFT JOIN tb_device d ON p.asset_type = 'device' AND d.id = p.asset_id").
|
||
Joins("LEFT JOIN tb_carrier ca ON ca.id = p.carrier_id").
|
||
Joins("LEFT JOIN tb_account a1 ON a1.id = p.closed_by").
|
||
Joins("LEFT JOIN tb_account a2 ON a2.id = p.restored_by").
|
||
Order("p.closed_at DESC, p.id DESC").Offset(offset).Limit(limit).Scan(&rows).Error
|
||
if err != nil {
|
||
return nil, errors.Wrap(errors.CodeDatabaseError, err, "查询不轮询清单失败")
|
||
}
|
||
return rows, nil
|
||
}
|