修复停复机忽略免实名策略并归档变更
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled

This commit is contained in:
2026-09-07 10:06:17 +08:00
parent 370fd3e67f
commit 5424751993
7 changed files with 170 additions and 11 deletions

View File

@@ -249,10 +249,25 @@ func (s *StopResumeService) isTrafficExhausted(ctx context.Context, card *model.
}
// isRealnameOK 检查卡是否满足实名要求
// 行业卡card_category='industry')无需实名;其他卡需 real_name_status=1
func (s *StopResumeService) isRealnameOK(card *model.IotCard) bool {
return card.CardCategory == constants.CardCategoryIndustry ||
card.RealNameStatus == constants.RealNameStatusVerified
// 行业卡、已实名卡直接放行;其他卡按有效设备或自身的无需实名策略判断。
func (s *StopResumeService) isRealnameOK(ctx context.Context, card *model.IotCard) (bool, error) {
if card.CardCategory == constants.CardCategoryIndustry || card.RealNameStatus == constants.RealNameStatusVerified {
return true, nil
}
deviceID, bound, err := s.getCardDeviceID(ctx, card)
if err != nil {
return false, errors.Wrap(errors.CodeDatabaseError, err, "查询卡实名策略绑定关系失败")
}
if !bound {
return card.RealnamePolicy == constants.RealnamePolicyNone, nil
}
var device model.Device
if err := s.db.WithContext(ctx).Select("realname_policy").First(&device, deviceID).Error; err != nil {
return false, errors.Wrap(errors.CodeDatabaseError, err, "查询设备实名策略失败")
}
return device.RealnamePolicy == constants.RealnamePolicyNone, nil
}
// checkStopReasons 检查卡的停机原因列表,按优先级排序
@@ -278,8 +293,12 @@ func (s *StopResumeService) checkStopReasons(ctx context.Context, card *model.Io
reasons = append(reasons, constants.StopReasonNoPackage)
}
// 条件C非行业卡且未实名
if !s.isRealnameOK(card) {
// 条件C不满足实际生效的实名要求
realnameOK, err := s.isRealnameOK(ctx, card)
if err != nil {
return nil, err
}
if !realnameOK {
reasons = append(reasons, constants.StopReasonNotRealname)
}
@@ -305,7 +324,7 @@ func (s *StopResumeService) shouldResume(ctx context.Context, card *model.IotCar
return false, nil
}
return s.isRealnameOK(card), nil
return s.isRealnameOK(ctx, card)
}
// stopDeviceCards 停机设备下所有在线卡(含设备维度幂等锁)
@@ -349,7 +368,7 @@ func (s *StopResumeService) stopDeviceCards(ctx context.Context, deviceID uint,
}
// resumeDeviceCards 复机设备下满足条件的停机卡(含设备维度幂等锁)
// 遍历时对每张卡检查实名状态:未实名普通卡更新 stop_reason='not_realname' 后跳过
// 遍历时对每张卡检查有效实名策略:不满足要求的卡更新 stop_reason='not_realname' 后跳过
func (s *StopResumeService) resumeDeviceCards(ctx context.Context, deviceID uint) error {
// 设备维度幂等锁:与 stopDeviceCards 共用,防止停/复机并发
lockKey := constants.RedisPollingDeviceOpLockKey(deviceID)
@@ -374,7 +393,14 @@ func (s *StopResumeService) resumeDeviceCards(ctx context.Context, deviceID uint
var cardErrors []error
for _, card := range cards {
if !s.isRealnameOK(card) {
realnameOK, realnameErr := s.isRealnameOK(ctx, card)
if realnameErr != nil {
cardErrors = append(cardErrors, realnameErr)
s.logger.Warn("检查设备卡实名策略失败,继续处理其他卡",
zap.Uint("device_id", deviceID), zap.Uint("card_id", card.ID), zap.Error(realnameErr))
continue
}
if !realnameOK {
if updateErr := s.updateCardStopReasonWithAudit(ctx, card, constants.StopReasonNotRealname); updateErr != nil {
cardErrors = append(cardErrors, updateErr)
s.logger.Warn("更新未实名卡停机原因失败",
@@ -763,7 +789,12 @@ func (s *StopResumeService) ManualStopCard(ctx context.Context, iccid string) er
}
actionCode, summary := stopAuditAction(ctx, constants.StopReasonManual)
if !s.isRealnameOK(card) {
realnameOK, err := s.isRealnameOK(ctx, card)
if err != nil {
s.recordCardCommandAudit(ctx, card, actionCode, summary+"失败", constants.AuditResultFailed, "", cardSnapshot(card), nil, err)
return err
}
if !realnameOK {
denyErr := errors.New(errors.CodeForbidden, "卡未实名,无法操作")
s.recordCardCommandAudit(ctx, card, actionCode, summary+"被拒绝", constants.AuditResultDenied, "", cardSnapshot(card), nil, denyErr)
return denyErr
@@ -815,7 +846,12 @@ func (s *StopResumeService) ManualStartCard(ctx context.Context, iccid string) e
return denyErr
}
if !s.isRealnameOK(card) {
realnameOK, err := s.isRealnameOK(ctx, card)
if err != nil {
s.recordCardCommandAudit(ctx, card, actionCode, summary+"失败", constants.AuditResultFailed, "", cardSnapshot(card), nil, err)
return err
}
if !realnameOK {
denyErr := errors.New(errors.CodeForbidden, "卡未实名,无法操作")
s.recordCardCommandAudit(ctx, card, actionCode, summary+"被拒绝", constants.AuditResultDenied, "", cardSnapshot(card), nil, denyErr)
return denyErr