fix: 第1批 M9 H5 进入资产的临期个人通知写入即已读
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 12m9s

H5 进入资产时已同步弹窗展示临期提醒,通知中心再记未读会重复提醒;
通知按剩余天数每天新增一条,保持未读会持续累积红点。
直发通知载荷新增可选 mark_read,仅临期个人通知设置,其他直发通知与店铺临期通知仍为未读。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
邹进
2026-10-14 10:45:20 +09:00
parent eb98478b09
commit 713045a657
6 changed files with 35 additions and 4 deletions

View File

@@ -27,6 +27,8 @@ type AdminDirectPayload struct {
RefID string `json:"ref_id,omitempty"`
RefKey string `json:"ref_key,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
// MarkRead 为 true 时通知写入即已读,用于投递同时已在前端展示过的场景;缺省按未读写入。
MarkRead bool `json:"mark_read,omitempty"`
}
// PersonalCustomerDirectPayload 是明确个人客户通知的结构化 Outbox 载荷。
@@ -52,6 +54,7 @@ type deliveryRequest struct {
refKey string
expiresAt *time.Time
popupSnapshot *model.NotificationPopupSnapshot
markRead bool
}
// DeliveryService 校验接收人并幂等生成站内通知。
@@ -102,6 +105,7 @@ func (s *DeliveryService) consumeDirect(ctx context.Context, envelope outbox.Del
request := deliveryRequest{
notificationType: payload.NotificationType, templateData: payload.TemplateData,
refType: payload.RefType, refID: payload.RefID, refKey: payload.RefKey, expiresAt: payload.ExpiresAt,
markRead: payload.MarkRead,
}
if err := validateDeliveryRequest(request); err != nil {
return err
@@ -248,6 +252,11 @@ func (s *DeliveryService) deliverOne(ctx context.Context, eventID, recipientKind
RefType: request.refType, RefID: request.refID, RefKey: request.refKey,
ExpiresAt: prepared.expiresAt, CreatedAt: prepared.now, PopupSnapshot: request.popupSnapshot,
}
if request.markRead {
readAt := prepared.now
notification.IsRead = true
notification.ReadAt = &readAt
}
created := false
err = s.repository.DB().WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var createErr error
@@ -263,7 +272,7 @@ func (s *DeliveryService) deliverOne(ctx context.Context, eventID, recipientKind
Metadata: map[string]any{"outbox_event_id": eventID},
Resources: []audit.ResourceInput{audit.NotificationResource(notification,
constants.AuditResourceRelationPrimary, constants.AuditResourceRoleNotificationTarget,
nil, map[string]any{"created": true, "is_read": false})},
nil, map[string]any{"created": true, "is_read": notification.IsRead})},
})
})
if err != nil {

View File

@@ -108,6 +108,8 @@ func (p *ReminderPublisher) appendNotification(ctx context.Context, tx *gorm.DB,
RecipientID: customerID, NotificationType: constants.NotificationTypePackageExpiring,
TemplateData: expiryTemplateData(candidate), RefType: constants.NotificationRefTypeAsset,
RefID: assetID, RefKey: candidate.Identifier, ExpiresAt: candidate.EstimatedFinalExpiresAt,
// 进入资产时 H5 已同步弹窗展示该提醒,通知写入即已读,避免通知中心重复红点。
MarkRead: true,
},
})
if err != nil {