All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m23s
新增 000225 迁移:运营弹窗配置表 tb_h5_popup_configuration(页面/范围/优先级/频率/受控动作/启停/有效期/版本) 与 tb_notification 可空 JSONB 列 popup_snapshot。 新增通知直建窄接口 DirectWriter.CreateOrGetPersonal:与 Outbox 消费共用 prepareDelivery 的渲染、 展示期与 CreateIdempotent 规则,冲突时回查返回既有行;同步扩展个人通知查询与已读两处类型白名单, 并按个人客户入口补齐投递审计来源。 新增 H5 候选与风险换卡:GET /api/c/v1/popup-candidates 先判风险资格(广电卡 + 风险停机 + 无活动物流换货单),命中只返回风险候选;未命中再按时间/启停/页面/店铺/设备类型/卡类型范围/频率 匹配运营配置。POST /api/c/v1/risk-exchanges/:asset_id/address 锁资产行后幂等创建待发货物流换货单, 首次地址锁定,不沿用资产级群发通知。 新增后台运营弹窗配置 CRUD 与启停(仅超级管理员与平台账号),更新递增版本并刷新最近更新时间, 标题与正文统一拒绝 URL 与前端路由,全部写操作记录操作者、前后值、版本与时间。 同步 OpenAPI(cmd/gendocs、cmd/api/docs.go、pkg/openapi/handlers.go)与参数校验中文提示共用实现。
107 lines
9.3 KiB
Go
107 lines
9.3 KiB
Go
package dto
|
||
|
||
import "time"
|
||
|
||
// NotificationUnreadCountResponse 是后台账号未读数投影。
|
||
type NotificationUnreadCountResponse struct {
|
||
Count int64 `json:"count" description:"未读通知数量"`
|
||
DisplayCount string `json:"display_count" description:"徽标显示文本,超过 99 时为 99+"`
|
||
}
|
||
|
||
// NotificationListRequest 是后台通知基础分页参数。
|
||
type NotificationListRequest struct {
|
||
Category string `json:"category" query:"category" validate:"omitempty,oneof=approval expiry sync system" enums:"approval,expiry,sync,system" description:"通知类别 (approval:审批, expiry:临期, sync:同步, system:系统)"`
|
||
Type string `json:"type" query:"type" validate:"omitempty,oneof=system.notice package.expiring agent.recharge.completed refund.completed exchange.shipping.created agent.main_wallet.low_balance h5.popup.risk_exchange h5.popup.operation" enums:"system.notice,package.expiring,agent.recharge.completed,refund.completed,exchange.shipping.created,agent.main_wallet.low_balance,h5.popup.risk_exchange,h5.popup.operation" description:"稳定通知类型 (system.notice:系统通知, package.expiring:套餐临期, agent.recharge.completed:店铺充值入账, refund.completed:店铺退款完成, exchange.shipping.created:换货申请待处理, agent.main_wallet.low_balance:主钱包低余额, h5.popup.risk_exchange:风险换卡弹窗, h5.popup.operation:运营弹窗)"`
|
||
Severity string `json:"severity" query:"severity" validate:"omitempty,oneof=info warning error critical" enums:"info,warning,error,critical" description:"通知级别 (info:提示, warning:警告, error:错误, critical:严重)"`
|
||
IsRead *bool `json:"is_read" query:"is_read" description:"已读状态;不传时查询全部"`
|
||
Page int `json:"page" query:"page" validate:"omitempty,min=1,max=10000" minimum:"1" maximum:"10000" description:"页码,默认 1,最大 10000"`
|
||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=50" minimum:"1" maximum:"50" description:"每页数量,默认 20,最大 50"`
|
||
}
|
||
|
||
// NotificationItem 是后台账号可见的站内通知投影。
|
||
type NotificationItem struct {
|
||
ID uint `json:"id" description:"通知ID"`
|
||
Category string `json:"category" enums:"approval,expiry,sync,system" description:"通知类别 (approval:审批, expiry:临期, sync:同步, system:系统)"`
|
||
Type string `json:"type" enums:"system.notice,package.expiring,agent.recharge.completed,refund.completed,exchange.shipping.created,agent.main_wallet.low_balance,h5.popup.risk_exchange,h5.popup.operation" description:"稳定通知类型 (system.notice:系统通知, package.expiring:套餐临期, agent.recharge.completed:店铺充值入账, refund.completed:店铺退款完成, exchange.shipping.created:换货申请待处理, agent.main_wallet.low_balance:主钱包低余额, h5.popup.risk_exchange:风险换卡弹窗, h5.popup.operation:运营弹窗)"`
|
||
Severity string `json:"severity" enums:"info,warning,error,critical" description:"通知级别 (info:提示, warning:警告, error:错误, critical:严重)"`
|
||
Title string `json:"title" description:"纯文本标题"`
|
||
Body string `json:"body" description:"纯文本正文"`
|
||
RefType string `json:"ref_type" description:"受控资源类型;可能为空。可选值及含义:system_config:系统配置, integration_log:外部集成日志, package:套餐, asset:C端资产, refund:退款, agent_recharge:代理充值, wecom_approval:企微审批, iot_card:物联网卡, device:设备, expiring_asset:临期资产列表, shop_fund:店铺资金概况, card_sync:卡同步记录。后台点击通知应调用目标解析接口,不得直接拼接路由"`
|
||
RefID string `json:"ref_id" description:"受控资源数字ID的十进制字符串;可能为空。refund、agent_recharge、wecom_approval、iot_card、device、expiring_asset、shop_fund、asset 等类型使用;仅用于资源定位,不是前端URL"`
|
||
RefKey string `json:"ref_key" description:"受控资源稳定Key或展示快照;可能为空。system_config 为配置Key,integration_log/card_sync 为集成标识,asset 为资产标识快照;仅用于定位或展示,不是前端URL"`
|
||
IsRead bool `json:"is_read" description:"是否已读"`
|
||
ReadAt *time.Time `json:"read_at,omitempty" description:"首次已读时间(ISO 8601)"`
|
||
CreatedAt time.Time `json:"created_at" description:"创建时间(ISO 8601)"`
|
||
// PopupSnapshot 仅弹窗投放类型返回;其他通知类型为空。只包含配置标识、资产关联与受控动作,不含任何 URL 或前端路由。
|
||
PopupSnapshot *NotificationPopupSnapshotItem `json:"popup_snapshot,omitempty" description:"弹窗投放快照;仅 h5.popup.risk_exchange 与 h5.popup.operation 返回,其他通知类型为空"`
|
||
}
|
||
|
||
// NotificationPopupSnapshotItem 是弹窗投放通知冻结的快照投影,不含任何 URL 或前端路由。
|
||
type NotificationPopupSnapshotItem struct {
|
||
ConfigID uint `json:"config_id" description:"运营弹窗配置ID;风险换卡弹窗没有配置,固定为 0"`
|
||
ConfigVersion int64 `json:"config_version" description:"投放时的配置版本;风险换卡弹窗固定为 0。旧版本通知保留原快照不被改写"`
|
||
AssetType string `json:"asset_type" enums:"iot_card,device" description:"弹窗关联资产类型 (iot_card:物联网卡, device:设备)"`
|
||
AssetID uint `json:"asset_id" description:"弹窗关联资产数字ID"`
|
||
ActionType string `json:"action_type,omitempty" enums:"package_purchase,asset_wallet_recharge" description:"受控动作 (package_purchase:套餐购买, asset_wallet_recharge:资产钱包充值);为空表示无受控动作。前端按白名单映射页面,不得由后端下发 URL 或前端路由"`
|
||
}
|
||
|
||
// NotificationListResponse 是后台通知基础分页结果。
|
||
type NotificationListResponse struct {
|
||
Items []NotificationItem `json:"items" description:"通知列表"`
|
||
Total int64 `json:"total" description:"总数量"`
|
||
Page int `json:"page" description:"页码"`
|
||
Size int `json:"size" description:"每页数量"`
|
||
}
|
||
|
||
// NotificationIDParams 是单条通知路径参数。
|
||
type NotificationIDParams struct {
|
||
ID uint `json:"id" path:"id" required:"true" description:"通知ID"`
|
||
}
|
||
|
||
// NotificationReadResponse 是单条通知幂等已读结果。
|
||
type NotificationReadResponse struct {
|
||
Success bool `json:"success" description:"请求是否成功;通知不存在、属于别人或已经已读也返回 true"`
|
||
}
|
||
|
||
// NotificationTargetResponse 是通知受控目标解析结果,不包含任意 URL。
|
||
type NotificationTargetResponse struct {
|
||
TargetType string `json:"target_type" description:"前端白名单目标类型;空表示不支持跳转。可选值:refund_detail、agent_recharge_detail、wecom_approval_detail、iot_card_detail、device_detail、expiring_asset_list、shop_fund_summary、integration_log、system_config"`
|
||
TargetID *uint `json:"target_id,omitempty" description:"ID型目标的业务主键;前端按 target_type 映射受控页面,不得自行拼接任意URL"`
|
||
TargetKey string `json:"target_key,omitempty" description:"Key型目标的稳定定位值;仅用于 integration_log 或 system_config 等白名单目标"`
|
||
Available bool `json:"available" description:"当前账号是否仍可访问目标;false 时只展示通知正文,不执行跳转"`
|
||
}
|
||
|
||
// NotificationUnreadSummaryResponse 是后台账号未读通知的固定分类汇总。
|
||
type NotificationUnreadSummaryResponse struct {
|
||
Total int64 `json:"total" description:"未读通知总数"`
|
||
Approval int64 `json:"approval" description:"审批类未读数量"`
|
||
Expiry int64 `json:"expiry" description:"临期类未读数量"`
|
||
Sync int64 `json:"sync" description:"同步类未读数量"`
|
||
System int64 `json:"system" description:"系统类未读数量"`
|
||
}
|
||
|
||
// NotificationReadAllRequest 是后台批量已读请求。
|
||
type NotificationReadAllRequest struct {
|
||
Category string `json:"category" validate:"omitempty,oneof=approval expiry sync system" enums:"approval,expiry,sync,system" description:"可选通知类别 (approval:审批, expiry:临期, sync:同步, system:系统)"`
|
||
}
|
||
|
||
// NotificationReadAllResponse 是后台批量已读结果。
|
||
type NotificationReadAllResponse struct {
|
||
UpdatedCount int64 `json:"updated_count" description:"本次实际更新的通知数量"`
|
||
}
|
||
|
||
// PersonalNotificationListRequest 是个人客户通知的简化分页参数。
|
||
type PersonalNotificationListRequest struct {
|
||
IsRead *bool `json:"is_read" query:"is_read" description:"已读状态;false 仅查询未读,true 仅查询已读,不传时查询全部"`
|
||
Page int `json:"page" query:"page" validate:"omitempty,min=1,max=10000" minimum:"1" maximum:"10000" description:"页码,默认 1,最大 10000"`
|
||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=50" minimum:"1" maximum:"50" description:"每页数量,默认 20,最大 50"`
|
||
}
|
||
|
||
// PersonalNotificationListResponse 是个人客户通知的简化分页结果。
|
||
type PersonalNotificationListResponse struct {
|
||
Items []NotificationItem `json:"items" description:"当前个人客户可见的业务通知列表"`
|
||
Total int64 `json:"total" description:"总数量"`
|
||
Page int `json:"page" description:"页码"`
|
||
Size int `json:"size" description:"每页数量"`
|
||
}
|