59eb34976a
iotlcm-admin-svr:管理后台服务。 - Go module:iotlcm → git.5iot.com/iotlcm-public/iotlcm-admin-svr(729 文件) - 凭据与地址脱敏:JWT signingKey(含代码里的 MustGet 默认值)、 MySQL DSN、Redis 口令、告警邮件发件人邮箱全部改为占位; 私网 IP → 文档地址段;库名 xiujie_admin → iotlcm - 真实手机号/邮箱 → 合法 11 位编造号 / example.com - 移除内部资产:CI 触发器、过时 DDL(sql/db_iotlcm.sql)、 私有依赖 go get 行、明文 registry 登录口令 - 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名 - Dockerfile 改用公共基础镜像 - 拼错的 RADEME.md → README.md,README 重写 - 需要真实数据库的用例改为可用 IOTLCM_TEST_WITH_DB=1 显式启用 - 补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 数据库 schema 不随本仓发布(生产 DDL 已过时),README 已说明。
701 lines
20 KiB
Go
701 lines
20 KiB
Go
package simwarning
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
"net/mail"
|
||
"strings"
|
||
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts"
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/handler"
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/do"
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity"
|
||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service"
|
||
|
||
"github.com/gogf/gf/v2/database/gdb"
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
)
|
||
|
||
func (s *sSimWarning) ConfigList(ctx context.Context, in *model.SimWarningConfigListParam) (list []*model.SimWarningConfigModel, totalCount int, err error) {
|
||
if in == nil {
|
||
in = &model.SimWarningConfigListParam{}
|
||
}
|
||
if in.Page <= 0 {
|
||
in.Page = 1
|
||
}
|
||
if in.PageSize <= 0 {
|
||
in.PageSize = 20
|
||
}
|
||
|
||
mod := s.configModel(ctx)
|
||
columns := dao.TWarnConfig.Columns()
|
||
if in.Id > 0 {
|
||
mod = mod.Where(columns.Id, in.Id)
|
||
}
|
||
if in.ItemType > 0 {
|
||
mod = mod.Where(columns.ItemType, in.ItemType)
|
||
}
|
||
if in.ItemId > 0 {
|
||
mod = mod.Where(columns.ItemId, in.ItemId)
|
||
}
|
||
if in.WarnUnit > 0 {
|
||
if in.WarnUnit == warnUnitDay || in.WarnUnit == warnUnitMonth {
|
||
mod = mod.Where("1 = 0")
|
||
} else {
|
||
mod = mod.Where(columns.WarnUnit, in.WarnUnit)
|
||
}
|
||
} else if in.WarnType > 0 {
|
||
mod = applyWarnTypeCompatibilityFilter(mod, in.WarnType)
|
||
}
|
||
if in.IsEnabled != nil {
|
||
mod = mod.Where(columns.IsEnabled, *in.IsEnabled)
|
||
}
|
||
if itemCode := strings.TrimSpace(in.ItemCode); itemCode != "" {
|
||
mod = mod.WhereLike(columns.ItemCode, "%"+itemCode+"%")
|
||
}
|
||
if keyword := strings.TrimSpace(in.Keyword); keyword != "" {
|
||
mod = mod.WhereLike(columns.ItemCode, "%"+keyword+"%")
|
||
}
|
||
|
||
err = mod.Page(in.Page, in.PageSize).
|
||
OrderDesc(columns.Id).
|
||
ScanAndCount(&list, &totalCount, false)
|
||
if err != nil {
|
||
return nil, 0, gerror.Wrap(err, "获取预警配置列表失败,请稍后重试")
|
||
}
|
||
if list == nil {
|
||
list = []*model.SimWarningConfigModel{}
|
||
}
|
||
fillConfigWarnTypes(list)
|
||
return list, totalCount, nil
|
||
}
|
||
|
||
func (s *sSimWarning) ConfigView(ctx context.Context, in *model.SimWarningConfigViewParam) (res *model.SimWarningConfigModel, err error) {
|
||
if in == nil || (in.Id <= 0 && in.ItemId <= 0) {
|
||
return nil, gerror.New("配置ID和对象ID不能同时为空")
|
||
}
|
||
|
||
mod := s.configModel(ctx)
|
||
columns := dao.TWarnConfig.Columns()
|
||
if in.Id > 0 {
|
||
mod = mod.Where(columns.Id, in.Id)
|
||
} else {
|
||
itemType := in.ItemType
|
||
if itemType == 0 {
|
||
itemType = warnItemTypeCard
|
||
}
|
||
if itemType != warnItemTypeCard && itemType != warnItemTypeFlowPool {
|
||
return nil, gerror.New("预警对象类型无效")
|
||
}
|
||
warnUnit, err := warnUnitForConfigLookup(itemType, in.WarnType, in.WarnUnit)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
mod = mod.Where(columns.ItemType, itemType).
|
||
Where(columns.ItemId, in.ItemId).
|
||
Where(columns.WarnUnit, warnUnit)
|
||
}
|
||
if err = mod.Scan(&res); err != nil {
|
||
return nil, gerror.Wrap(err, "获取预警配置详情失败,请稍后重试")
|
||
}
|
||
if res == nil || res.Id == 0 {
|
||
return nil, gerror.New("预警配置不存在或无权限访问")
|
||
}
|
||
if res.WarnUnit == warnUnitDay || res.WarnUnit == warnUnitMonth {
|
||
return nil, gerror.New("日期预警由系统默认规则处理,不支持查询用户配置")
|
||
}
|
||
res.WarnType = deriveWarnType(res.ItemType, res.WarnUnit)
|
||
return res, nil
|
||
}
|
||
|
||
func (s *sSimWarning) ConfigSave(ctx context.Context, in *model.SimWarningConfigSaveParam) (res *model.SimWarningConfigSaveModel, err error) {
|
||
if in == nil {
|
||
return nil, gerror.New("请求参数不能为空")
|
||
}
|
||
user := contexts.GetUser(ctx)
|
||
if user == nil || user.TenantId == "" || user.ID == 0 {
|
||
return nil, gerror.New("登录信息已过期")
|
||
}
|
||
in.ItemCode = strings.TrimSpace(in.ItemCode)
|
||
itemType := in.ItemType
|
||
if itemType == 0 {
|
||
itemType = warnItemTypeCard
|
||
}
|
||
in.ItemType = itemType
|
||
if err = normalizeConfigSaveParam(in); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var itemCode string
|
||
switch in.ItemType {
|
||
case warnItemTypeCard:
|
||
card, err := s.queryConfigCard(ctx, in.ItemId, in.ItemCode)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
in.ItemId = card.Id
|
||
itemCode = strings.TrimSpace(in.ItemCode)
|
||
if itemCode == "" {
|
||
itemCode = strings.TrimSpace(card.Iccid)
|
||
}
|
||
if itemCode == "" {
|
||
itemCode = strings.TrimSpace(card.Msisdn)
|
||
}
|
||
case warnItemTypeFlowPool:
|
||
pool, err := s.queryConfigFlowPool(ctx, in.ItemId, in.ItemCode)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
in.ItemId = pool.Id
|
||
itemCode = strings.TrimSpace(in.ItemCode)
|
||
if itemCode == "" {
|
||
itemCode = strings.TrimSpace(pool.FlowPoolCode)
|
||
}
|
||
default:
|
||
return nil, gerror.New("预警对象类型无效")
|
||
}
|
||
if err = s.ensureConfigWritable(ctx, user.TenantId, in.Id, in.ItemType, in.ItemId, in.WarnUnit); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
now := gtime.Now()
|
||
data := buildConfigSaveData(user.TenantId, user.DeptId, user.ID, itemCode, in, now)
|
||
columns := dao.TWarnConfig.Columns()
|
||
_, err = dao.TWarnConfig.Ctx(ctx).
|
||
Data(data).
|
||
OnConflict(columns.TenantId, columns.ItemType, columns.ItemId, columns.WarnUnit).
|
||
OnDuplicateEx(strings.Join([]string{
|
||
columns.Id,
|
||
columns.TenantId,
|
||
columns.ItemType,
|
||
columns.ItemId,
|
||
columns.WarnUnit,
|
||
columns.CreatedDept,
|
||
columns.CreatedBy,
|
||
columns.CreatedAt,
|
||
}, ",")).
|
||
Save()
|
||
if err != nil {
|
||
return nil, gerror.Wrap(err, "保存预警配置失败,请稍后重试")
|
||
}
|
||
|
||
saved, err := s.findConfigByItem(ctx, user.TenantId, in.ItemType, in.ItemId, in.WarnUnit, true)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if saved == nil || saved.Id == 0 {
|
||
return nil, gerror.New("保存预警配置后未查询到配置")
|
||
}
|
||
return &model.SimWarningConfigSaveModel{Id: saved.Id}, nil
|
||
}
|
||
|
||
func (s *sSimWarning) ConfigStatus(ctx context.Context, in *model.SimWarningConfigStatusParam) (err error) {
|
||
if in == nil || in.Id <= 0 {
|
||
return gerror.New("配置ID不能为空")
|
||
}
|
||
if in.IsEnabled != 0 && in.IsEnabled != 1 {
|
||
return gerror.New("启停状态无效")
|
||
}
|
||
if _, err = s.ConfigView(ctx, &model.SimWarningConfigViewParam{Id: in.Id}); err != nil {
|
||
return err
|
||
}
|
||
userId := contexts.GetUserId(ctx)
|
||
columns := dao.TWarnConfig.Columns()
|
||
result, err := s.configModel(ctx).Where(columns.Id, in.Id).Data(do.TWarnConfig{
|
||
IsEnabled: in.IsEnabled,
|
||
UpdatedBy: userId,
|
||
UpdatedAt: gtime.Now(),
|
||
}).Update()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "启停预警配置失败,请稍后重试")
|
||
}
|
||
return ensureAffected(result, "预警配置不存在或无权限访问")
|
||
}
|
||
|
||
func (s *sSimWarning) ConfigDelete(ctx context.Context, in *model.SimWarningConfigDeleteParam) (err error) {
|
||
if in == nil || in.Id <= 0 {
|
||
return gerror.New("配置ID不能为空")
|
||
}
|
||
if _, err = s.ConfigView(ctx, &model.SimWarningConfigViewParam{Id: in.Id}); err != nil {
|
||
return err
|
||
}
|
||
result, err := s.configModel(ctx).Where(dao.TWarnConfig.Columns().Id, in.Id).Delete()
|
||
if err != nil {
|
||
return gerror.Wrap(err, "删除预警配置失败,请稍后重试")
|
||
}
|
||
return ensureAffected(result, "预警配置不存在或无权限访问")
|
||
}
|
||
|
||
func (s *sSimWarning) configModel(ctx context.Context) *gdb.Model {
|
||
return handler.Model(dao.TWarnConfig.Ctx(ctx)).
|
||
Fields(warningConfigFields()...)
|
||
}
|
||
|
||
func (s *sSimWarning) queryConfigCard(ctx context.Context, itemId int64, itemCode string) (*entity.TSimCardInfo, error) {
|
||
itemCode = strings.TrimSpace(itemCode)
|
||
if itemId <= 0 && itemCode == "" {
|
||
return nil, gerror.New("单卡ID或ICCID/MSISDN/IMSI不能为空")
|
||
}
|
||
var card *entity.TSimCardInfo
|
||
mod := service.IotTSimCardInfo().Model(ctx).Fields(
|
||
"id",
|
||
"iccid",
|
||
"msisdn",
|
||
"imsi",
|
||
"tenant_id",
|
||
)
|
||
if itemId > 0 {
|
||
mod = mod.Where("id", itemId)
|
||
} else {
|
||
mod = mod.Where("(iccid = ? OR msisdn = ? OR imsi = ?)", itemCode, itemCode, itemCode)
|
||
}
|
||
if err := mod.Scan(&card); err != nil {
|
||
return nil, gerror.Wrap(err, "查询单卡失败,请稍后重试")
|
||
}
|
||
if card == nil || card.Id == 0 {
|
||
return nil, gerror.New("单卡不存在或无权限访问")
|
||
}
|
||
return card, nil
|
||
}
|
||
|
||
func (s *sSimWarning) queryConfigFlowPool(ctx context.Context, itemId int64, itemCode string) (*entity.TSimFlowPool, error) {
|
||
itemCode = strings.TrimSpace(itemCode)
|
||
if itemId <= 0 && itemCode == "" {
|
||
return nil, gerror.New("流量池ID或流量池编号不能为空")
|
||
}
|
||
var pool *entity.TSimFlowPool
|
||
mod := service.IotTSimFlowPool().Model(ctx).Fields(
|
||
"id",
|
||
"flow_pool_code",
|
||
"tenant_id",
|
||
)
|
||
if itemId > 0 {
|
||
mod = mod.Where("id", itemId)
|
||
} else {
|
||
mod = mod.Where("flow_pool_code", itemCode)
|
||
}
|
||
if err := mod.Scan(&pool); err != nil {
|
||
return nil, gerror.Wrap(err, "查询流量池失败,请稍后重试")
|
||
}
|
||
if pool == nil || pool.Id == 0 {
|
||
return nil, gerror.New("流量池不存在或无权限访问")
|
||
}
|
||
return pool, nil
|
||
}
|
||
|
||
func (s *sSimWarning) ensureConfigWritable(ctx context.Context, tenantId string, id int64, itemType int, itemId int64, warnUnit int) error {
|
||
if id > 0 {
|
||
existing, err := s.findConfigByID(ctx, tenantId, id, false)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if existing == nil || existing.Id == 0 {
|
||
return gerror.New("预警配置不存在")
|
||
}
|
||
if existing.ItemType != itemType || existing.ItemId != itemId || existing.WarnUnit != warnUnit {
|
||
return gerror.New("配置ID与对象或预警维度不匹配")
|
||
}
|
||
return s.ensureConfigVisible(ctx, existing.Id)
|
||
}
|
||
|
||
existing, err := s.findConfigByItem(ctx, tenantId, itemType, itemId, warnUnit, false)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if existing == nil || existing.Id == 0 {
|
||
return nil
|
||
}
|
||
return s.ensureConfigVisible(ctx, existing.Id)
|
||
}
|
||
|
||
func (s *sSimWarning) ensureConfigVisible(ctx context.Context, id int64) error {
|
||
visible, err := s.findConfigByID(ctx, "", id, true)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if visible == nil || visible.Id == 0 {
|
||
return gerror.New("预警配置不存在或无权限访问")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (s *sSimWarning) findConfigByID(ctx context.Context, tenantId string, id int64, withAuth bool) (*model.SimWarningConfigModel, error) {
|
||
if id <= 0 {
|
||
return nil, nil
|
||
}
|
||
columns := dao.TWarnConfig.Columns()
|
||
mod := dao.TWarnConfig.Ctx(ctx).
|
||
Fields(warningConfigFields()...).
|
||
Where(columns.Id, id)
|
||
if tenantId != "" {
|
||
mod = mod.Where(columns.TenantId, tenantId)
|
||
}
|
||
if withAuth {
|
||
mod = handler.Model(mod)
|
||
}
|
||
var res *model.SimWarningConfigModel
|
||
if err := mod.Scan(&res); err != nil {
|
||
return nil, gerror.Wrap(err, "查询预警配置失败,请稍后重试")
|
||
}
|
||
if res != nil {
|
||
res.WarnType = deriveWarnType(res.ItemType, res.WarnUnit)
|
||
}
|
||
return res, nil
|
||
}
|
||
|
||
func (s *sSimWarning) findConfigByItem(ctx context.Context, tenantId string, itemType int, itemId int64, warnUnit int, withAuth bool) (*model.SimWarningConfigModel, error) {
|
||
if tenantId == "" || itemId <= 0 || warnUnit <= 0 {
|
||
return nil, nil
|
||
}
|
||
if itemType == 0 {
|
||
itemType = warnItemTypeCard
|
||
}
|
||
columns := dao.TWarnConfig.Columns()
|
||
mod := dao.TWarnConfig.Ctx(ctx).
|
||
Fields(warningConfigFields()...).
|
||
Where(columns.TenantId, tenantId).
|
||
Where(columns.ItemType, itemType).
|
||
Where(columns.ItemId, itemId).
|
||
Where(columns.WarnUnit, warnUnit)
|
||
if withAuth {
|
||
mod = handler.Model(mod)
|
||
}
|
||
var res *model.SimWarningConfigModel
|
||
if err := mod.Scan(&res); err != nil {
|
||
return nil, gerror.Wrap(err, "查询预警配置失败,请稍后重试")
|
||
}
|
||
if res != nil {
|
||
res.WarnType = deriveWarnType(res.ItemType, res.WarnUnit)
|
||
}
|
||
return res, nil
|
||
}
|
||
|
||
func warningConfigFields() []any {
|
||
columns := dao.TWarnConfig.Columns()
|
||
return []any{
|
||
columns.Id,
|
||
columns.TenantId,
|
||
columns.BatchNo,
|
||
columns.ItemType,
|
||
columns.ItemId,
|
||
columns.ItemCode,
|
||
columns.WarnUnit,
|
||
columns.FirstWarn,
|
||
columns.SecondWarn,
|
||
columns.ThirdWarn,
|
||
columns.WarnMethods,
|
||
columns.WarnPhones,
|
||
columns.WarnEmails,
|
||
columns.AutoAction,
|
||
columns.IsEnabled,
|
||
columns.WxTemplateId,
|
||
columns.Remark,
|
||
columns.CreatedDept,
|
||
columns.CreatedBy,
|
||
columns.CreatedAt,
|
||
columns.UpdatedBy,
|
||
columns.UpdatedAt,
|
||
columns.AppNotifyEnabled,
|
||
}
|
||
}
|
||
|
||
func buildConfigSaveData(tenantId string, deptId int64, userId int64, resolvedItemCode string, in *model.SimWarningConfigSaveParam, now *gtime.Time) do.TWarnConfig {
|
||
itemCode := strings.TrimSpace(resolvedItemCode)
|
||
if itemCode == "" {
|
||
itemCode = strings.TrimSpace(in.ItemCode)
|
||
}
|
||
isEnabled := 1
|
||
if in.IsEnabled != nil {
|
||
isEnabled = *in.IsEnabled
|
||
}
|
||
warnMethods := normalizeConfigWarnMethods(in.WarnMethods)
|
||
data := do.TWarnConfig{
|
||
TenantId: tenantId,
|
||
ItemType: in.ItemType,
|
||
ItemId: in.ItemId,
|
||
ItemCode: itemCode,
|
||
BatchNo: strings.TrimSpace(in.BatchNo),
|
||
WarnUnit: in.WarnUnit,
|
||
FirstWarn: in.FirstWarn,
|
||
SecondWarn: in.SecondWarn,
|
||
ThirdWarn: in.ThirdWarn,
|
||
WarnMethods: warnMethods,
|
||
WarnPhones: strings.TrimSpace(in.WarnPhones),
|
||
WarnEmails: strings.TrimSpace(in.WarnEmails),
|
||
AutoAction: in.AutoAction,
|
||
Remark: strings.TrimSpace(in.Remark),
|
||
CreatedDept: deptId,
|
||
CreatedBy: userId,
|
||
CreatedAt: now,
|
||
UpdatedBy: userId,
|
||
UpdatedAt: now,
|
||
IsEnabled: isEnabled,
|
||
}
|
||
if in.AppNotifyEnabled != nil {
|
||
data.AppNotifyEnabled = *in.AppNotifyEnabled
|
||
}
|
||
return data
|
||
}
|
||
|
||
func normalizeConfigSaveParam(in *model.SimWarningConfigSaveParam) error {
|
||
in.ItemCode = strings.TrimSpace(in.ItemCode)
|
||
in.WarnMethods = normalizeConfigWarnMethods(in.WarnMethods)
|
||
in.WarnPhones = strings.TrimSpace(in.WarnPhones)
|
||
in.WarnEmails = strings.TrimSpace(in.WarnEmails)
|
||
in.Remark = strings.TrimSpace(in.Remark)
|
||
if in.ItemType == 0 {
|
||
in.ItemType = warnItemTypeCard
|
||
}
|
||
if in.ItemType != warnItemTypeCard && in.ItemType != warnItemTypeFlowPool {
|
||
return gerror.New("预警对象类型无效")
|
||
}
|
||
if in.ItemId <= 0 && in.ItemCode == "" {
|
||
if in.ItemType == warnItemTypeFlowPool {
|
||
return gerror.New("流量池ID或流量池编号不能为空")
|
||
}
|
||
return gerror.New("单卡ID或ICCID/MSISDN/IMSI不能为空")
|
||
}
|
||
if in.WarnUnit == warnUnitDay || in.WarnUnit == warnUnitMonth {
|
||
return gerror.New("日期预警由系统默认规则处理,不支持手动配置")
|
||
}
|
||
if err := normalizeConfigContacts(in); err != nil {
|
||
return err
|
||
}
|
||
if in.IsEnabled != nil && *in.IsEnabled != 0 && *in.IsEnabled != 1 {
|
||
return gerror.New("启停状态无效")
|
||
}
|
||
if in.AppNotifyEnabled != nil && *in.AppNotifyEnabled != 0 && *in.AppNotifyEnabled != 1 {
|
||
return gerror.New("小程序订阅通知状态无效")
|
||
}
|
||
if in.AutoAction != 0 && in.AutoAction != warnAutoActionDataCut {
|
||
return gerror.New("第三次是否断网配置无效")
|
||
}
|
||
if in.ItemType == warnItemTypeFlowPool && in.AutoAction != 0 {
|
||
return gerror.New("流量池预警不支持自动断网")
|
||
}
|
||
|
||
in.WarnType = deriveWarnType(in.ItemType, in.WarnUnit)
|
||
if err := validateWarnTypeUnit(in.ItemType, in.WarnType, in.WarnUnit); err != nil {
|
||
return err
|
||
}
|
||
if in.ItemType == warnItemTypeCard && in.AutoAction == warnAutoActionDataCut && in.ThirdWarn <= 0 {
|
||
return gerror.New("开启第三次断网时必须配置第三次提醒")
|
||
}
|
||
|
||
switch in.WarnType {
|
||
case warnTypeCardTraffic, warnTypeFlowPoolPercent:
|
||
if in.WarnUnit == warnUnitPercent {
|
||
first := normalizePercentThreshold(in.FirstWarn)
|
||
second := normalizePercentThreshold(in.SecondWarn)
|
||
third := normalizePercentThreshold(in.ThirdWarn)
|
||
if first > 100 || second > 100 || third > 100 {
|
||
return gerror.New("百分比阈值不能大于100")
|
||
}
|
||
in.FirstWarn = first
|
||
in.SecondWarn = second
|
||
in.ThirdWarn = third
|
||
}
|
||
return validateTrafficThresholds(in.FirstWarn, in.SecondWarn, in.ThirdWarn)
|
||
default:
|
||
return gerror.New("预警类型无效")
|
||
}
|
||
}
|
||
|
||
func normalizeConfigContacts(in *model.SimWarningConfigSaveParam) error {
|
||
if hasConfigWarnMethod(in.WarnMethods, "0") {
|
||
phones, err := normalizeConfigWarnPhones(in.WarnPhones)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
in.WarnPhones = phones
|
||
} else {
|
||
in.WarnPhones = ""
|
||
}
|
||
if hasConfigWarnMethod(in.WarnMethods, "1") {
|
||
emails, err := normalizeConfigWarnEmails(in.WarnEmails)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
in.WarnEmails = emails
|
||
} else {
|
||
in.WarnEmails = ""
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func hasConfigWarnMethod(methods string, target string) bool {
|
||
for _, method := range splitConfigWarnContactList(methods) {
|
||
if method == target {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
func normalizeConfigWarnMethods(methods string) string {
|
||
selected := map[string]struct{}{
|
||
warnMethodPlatform: {},
|
||
}
|
||
for _, method := range splitConfigWarnContactList(methods) {
|
||
switch method {
|
||
case warnMethodPlatform, warnMethodEmail, warnMethodSMS, warnMethodPhone:
|
||
selected[method] = struct{}{}
|
||
}
|
||
}
|
||
ordered := []string{
|
||
warnMethodPlatform,
|
||
warnMethodEmail,
|
||
warnMethodSMS,
|
||
warnMethodPhone,
|
||
}
|
||
result := make([]string, 0, len(ordered))
|
||
for _, method := range ordered {
|
||
if _, ok := selected[method]; ok {
|
||
result = append(result, method)
|
||
}
|
||
}
|
||
return strings.Join(result, ",")
|
||
}
|
||
|
||
func normalizeConfigWarnEmails(value string) (string, error) {
|
||
emails := splitConfigWarnContactList(value)
|
||
if len(emails) == 0 {
|
||
return "", gerror.New("请选择邮箱提醒时必须填写邮箱地址")
|
||
}
|
||
result := make([]string, 0, len(emails))
|
||
for _, email := range emails {
|
||
address, err := mail.ParseAddress(email)
|
||
if err != nil || address == nil || strings.TrimSpace(address.Address) == "" {
|
||
return "", gerror.Newf("邮箱格式不正确:%s", email)
|
||
}
|
||
result = append(result, strings.ToLower(strings.TrimSpace(address.Address)))
|
||
}
|
||
return strings.Join(result, ","), nil
|
||
}
|
||
|
||
func normalizeConfigWarnPhones(value string) (string, error) {
|
||
phones := splitConfigWarnContactList(value)
|
||
if len(phones) == 0 {
|
||
return "", gerror.New("请选择短信提醒时必须填写短信号码")
|
||
}
|
||
for _, phone := range phones {
|
||
if !isValidConfigWarnPhone(phone) {
|
||
return "", gerror.Newf("手机号格式不正确:%s", phone)
|
||
}
|
||
}
|
||
return strings.Join(phones, ","), nil
|
||
}
|
||
|
||
func isValidConfigWarnPhone(phone string) bool {
|
||
if len(phone) != 11 || phone[0] != '1' {
|
||
return false
|
||
}
|
||
for _, r := range phone {
|
||
if r < '0' || r > '9' {
|
||
return false
|
||
}
|
||
}
|
||
return phone[1] >= '3' && phone[1] <= '9'
|
||
}
|
||
|
||
func splitConfigWarnContactList(value string) []string {
|
||
parts := strings.FieldsFunc(value, func(r rune) bool {
|
||
switch r {
|
||
case ',', ';', ',', ';', '|', '\n', '\r', '\t', ' ':
|
||
return true
|
||
default:
|
||
return false
|
||
}
|
||
})
|
||
seen := make(map[string]struct{}, len(parts))
|
||
result := make([]string, 0, len(parts))
|
||
for _, part := range parts {
|
||
part = strings.TrimSpace(part)
|
||
if part == "" {
|
||
continue
|
||
}
|
||
key := strings.ToLower(part)
|
||
if _, exists := seen[key]; exists {
|
||
continue
|
||
}
|
||
seen[key] = struct{}{}
|
||
result = append(result, part)
|
||
}
|
||
return result
|
||
}
|
||
|
||
func validateTrafficThresholds(first, second, third float64) error {
|
||
if first <= 0 {
|
||
return gerror.New("第一档阈值必须大于0")
|
||
}
|
||
if second < 0 || third < 0 {
|
||
return gerror.New("预警阈值不能小于0")
|
||
}
|
||
if second > 0 && second <= first {
|
||
return gerror.New("流量预警第二档阈值必须大于第一档")
|
||
}
|
||
if third > 0 {
|
||
if second <= 0 {
|
||
return gerror.New("配置第三档时必须先配置第二档")
|
||
}
|
||
if third <= second {
|
||
return gerror.New("流量预警第三档阈值必须大于第二档")
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func warnUnitForConfigLookup(itemType, warnType, warnUnit int) (int, error) {
|
||
if warnUnit > 0 {
|
||
if warnUnit == warnUnitDay || warnUnit == warnUnitMonth {
|
||
return 0, gerror.New("日期预警由系统默认规则处理,不支持查询用户配置")
|
||
}
|
||
if err := validateWarnTypeUnit(itemType, deriveWarnType(itemType, warnUnit), warnUnit); err != nil {
|
||
return 0, err
|
||
}
|
||
return warnUnit, nil
|
||
}
|
||
switch warnType {
|
||
case warnTypeFlowPoolPercent:
|
||
return warnUnitPercent, nil
|
||
case warnTypeCardTraffic:
|
||
return 0, gerror.New("通过对象ID查询单卡流量预警时必须指定warnUnit")
|
||
default:
|
||
return 0, gerror.New("通过对象ID查询预警配置时必须指定warnUnit")
|
||
}
|
||
}
|
||
|
||
func applyWarnTypeCompatibilityFilter(mod *gdb.Model, warnType int) *gdb.Model {
|
||
switch warnType {
|
||
case warnTypeCardTraffic:
|
||
return mod.Where("item_type = ? AND warn_unit IN (?, ?)", warnItemTypeCard, warnUnitMb, warnUnitPercent)
|
||
case warnTypeFlowPoolPercent:
|
||
return mod.Where("item_type = ? AND warn_unit = ?", warnItemTypeFlowPool, warnUnitPercent)
|
||
default:
|
||
return mod.Where("1 = 0")
|
||
}
|
||
}
|
||
|
||
func fillConfigWarnTypes(list []*model.SimWarningConfigModel) {
|
||
for _, item := range list {
|
||
if item == nil {
|
||
continue
|
||
}
|
||
item.WarnType = deriveWarnType(item.ItemType, item.WarnUnit)
|
||
}
|
||
}
|
||
|
||
func ensureAffected(result sql.Result, message string) error {
|
||
affected, err := result.RowsAffected()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if affected == 0 {
|
||
return gerror.New(message)
|
||
}
|
||
return nil
|
||
}
|