Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
- 新增六对成对迁移 000232–000237:H5 弹窗类型、退款结算标识与申请人备注、优先轮询事实字段与两个新终态、通道阈值命中留痕、手机号最近解绑人、提现资格校验留痕 - 退款:原因必填与申请人备注、来源支付与渠道流水冻结、线下处理流水号补录审计、按订单查询可选退款方式、企微审批材料补齐且新增字段缺失映射即明确失败 - 优先轮询:人工关闭、有效期到期独立周期任务、失败与过期人工重触发、事实字段与异常重试查询、资产解析端点只读投影 - 通道阈值:命中事实同事务留痕与命中记录查询;员工账单:列表筛选与详情投影;商户池:列表投影与统计周期语义;H5:弹窗类型与类别排序 - 手机号:有效关联数量与最近解绑人、短信验证码失败次数限制;导出:佣金明细十五列与报表序号列 - 时间筛选:三处新增筛选纳入统一严格解析契约,员工账单产生时间参数改名 - 同步 12 份主 Spec 需求、两端点与异步任务证据链,门禁 context-health 与 OpenSpec 校验通过
152 lines
16 KiB
Go
152 lines
16 KiB
Go
package dto
|
||
|
||
import "time"
|
||
|
||
// CreateH5PopupConfigurationRequest 是创建 H5 运营弹窗配置的请求。
|
||
// 范围四维中只有 pages 必填;店铺、设备类型、卡类型不传或传空数组表示该维度全量。
|
||
// action_type 只接受受控动作白名单,不接受 URL、前端路由或任意参数。
|
||
type CreateH5PopupConfigurationRequest struct {
|
||
Title string `json:"title" validate:"required,min=1,max=100" required:"true" minLength:"1" maxLength:"100" description:"弹窗标题,1~100 字符;投放时冻结写入通知标题"`
|
||
Content string `json:"content" validate:"required,min=1,max=2000" required:"true" minLength:"1" maxLength:"2000" description:"弹窗正文,1~2000 字符;投放时冻结写入通知正文,不接受 HTML、URL 或前端路由"`
|
||
PopupType string `json:"popup_type" validate:"required,oneof=promotion announcement" required:"true" enum:"promotion,announcement" description:"弹窗类型,必填 (promotion:套餐政策推广, announcement:通用公告);类别优先级为风险换卡提醒 > 套餐政策推广 > 通用公告,类别优先于显式优先级"`
|
||
Pages []string `json:"pages" validate:"required,min=1,max=4,dive,oneof=home asset_detail package_purchase asset_wallet_recharge" required:"true" description:"命中页面集合,至少一项 (home:首页, asset_detail:资产详情, package_purchase:套餐购买, asset_wallet_recharge:资产钱包充值)"`
|
||
ShopIDs []uint `json:"shop_ids" validate:"omitempty,max=200,dive,min=1" maxLength:"200" description:"店铺范围;不传或空数组表示全量,同维度多选取任一命中"`
|
||
DeviceTypes []string `json:"device_types" validate:"omitempty,max=100,dive,min=1,max=50" maxLength:"100" description:"设备类型范围;不传或空数组表示全量;资产该维度无值(独立卡或未绑定设备)时不命中已配置范围"`
|
||
CardTypes []string `json:"card_types" validate:"omitempty,max=4,dive,oneof=CMCC CUCC CTCC CBN" maxLength:"4" description:"卡类型范围 (CMCC:中国移动, CUCC:中国联通, CTCC:中国电信, CBN:中国广电);不传或空数组表示全量;非卡资产该维度无值时不命中已配置范围"`
|
||
Priority *int `json:"priority" validate:"omitempty,min=0,max=1000000" minimum:"0" maximum:"1000000" description:"优先级,数值越大越优先,默认 0"`
|
||
Frequency string `json:"frequency" validate:"required,oneof=once daily" required:"true" enum:"once,daily" description:"投放频率 (once:每客户每配置版本仅一次, daily:每客户每配置版本每个上海自然日一次)"`
|
||
Enabled *bool `json:"enabled" description:"是否启用;不传按停用创建"`
|
||
ActionType *string `json:"action_type" validate:"omitempty,oneof=package_purchase asset_wallet_recharge" enum:"package_purchase,asset_wallet_recharge" description:"受控动作 (package_purchase:套餐购买, asset_wallet_recharge:资产钱包充值);不传表示无受控动作"`
|
||
StartsAt time.Time `json:"starts_at" validate:"required" required:"true" description:"生效开始时间(ISO 8601)"`
|
||
EndsAt time.Time `json:"ends_at" validate:"required" required:"true" description:"生效结束时间(ISO 8601),不得早于开始时间"`
|
||
}
|
||
|
||
// UpdateH5PopupConfigurationRequest 是更新 H5 运营弹窗配置的请求。
|
||
// 除范围集合外均为指针:字段缺省表示保持原值;范围字段传空数组表示该维度改为全量。
|
||
// 更新成功即递增配置版本,旧版本已投放通知的内容与快照不被改写。
|
||
type UpdateH5PopupConfigurationRequest struct {
|
||
Title *string `json:"title" validate:"omitempty,min=1,max=100" minLength:"1" maxLength:"100" description:"弹窗标题,1~100 字符;不传保持原值"`
|
||
Content *string `json:"content" validate:"omitempty,min=1,max=2000" minLength:"1" maxLength:"2000" description:"弹窗正文,1~2000 字符;不传保持原值,不接受 HTML、URL 或前端路由"`
|
||
PopupType *string `json:"popup_type" validate:"omitempty,oneof=promotion announcement" enum:"promotion,announcement" description:"弹窗类型 (promotion:套餐政策推广, announcement:通用公告);不传保持原值。类别优先级为风险换卡提醒 > 套餐政策推广 > 通用公告,类别优先于显式优先级"`
|
||
Pages *[]string `json:"pages" validate:"omitempty,min=1,max=4,dive,oneof=home asset_detail package_purchase asset_wallet_recharge" description:"命中页面集合;不传保持原值,传空数组等价于非法(页面必选)"`
|
||
ShopIDs *[]uint `json:"shop_ids" validate:"omitempty,max=200,dive,min=1" maxLength:"200" description:"店铺范围;不传保持原值,传空数组表示改为全量"`
|
||
DeviceTypes *[]string `json:"device_types" validate:"omitempty,max=100,dive,min=1,max=50" maxLength:"100" description:"设备类型范围;不传保持原值,传空数组表示改为全量"`
|
||
CardTypes *[]string `json:"card_types" validate:"omitempty,max=4,dive,oneof=CMCC CUCC CTCC CBN" maxLength:"4" description:"卡类型范围;不传保持原值,传空数组表示改为全量"`
|
||
Priority *int `json:"priority" validate:"omitempty,min=0,max=1000000" minimum:"0" maximum:"1000000" description:"优先级,数值越大越优先;不传保持原值"`
|
||
Frequency *string `json:"frequency" validate:"omitempty,oneof=once daily" enum:"once,daily" description:"投放频率 (once:每客户每配置版本仅一次, daily:每客户每配置版本每个上海自然日一次);不传保持原值"`
|
||
Enabled *bool `json:"enabled" description:"是否启用;不传保持原值。启停会刷新最近更新时间并影响同优先级排序"`
|
||
ActionType *string `json:"action_type" validate:"omitempty,oneof=package_purchase asset_wallet_recharge" enum:"package_purchase,asset_wallet_recharge" description:"受控动作;传空字符串表示清除受控动作,不传保持原值"`
|
||
StartsAt *time.Time `json:"starts_at" description:"生效开始时间(ISO 8601);不传保持原值"`
|
||
EndsAt *time.Time `json:"ends_at" description:"生效结束时间(ISO 8601);不传保持原值,不得早于开始时间"`
|
||
}
|
||
|
||
// H5PopupConfigurationIDParams 是运营弹窗配置的路径参数。
|
||
type H5PopupConfigurationIDParams struct {
|
||
ID uint `json:"id" path:"id" required:"true" description:"运营弹窗配置ID"`
|
||
}
|
||
|
||
// UpdateH5PopupConfigurationParams 是更新运营弹窗配置的路径参数与请求体。
|
||
// 路径字段必须由 Handler 从 c.Params 回填后再校验,避免 required 恒失败或被请求体覆盖。
|
||
type UpdateH5PopupConfigurationParams struct {
|
||
ID uint `json:"id" path:"id" required:"true" description:"运营弹窗配置ID"`
|
||
UpdateH5PopupConfigurationRequest
|
||
}
|
||
|
||
// H5PopupConfigurationResponse 是运营弹窗配置投影。
|
||
type H5PopupConfigurationResponse struct {
|
||
ID uint `json:"id" description:"配置ID"`
|
||
Title string `json:"title" description:"弹窗标题"`
|
||
Content string `json:"content" description:"弹窗正文"`
|
||
PopupType string `json:"popup_type" enums:"promotion,announcement" description:"弹窗类型 (promotion:套餐政策推广, announcement:通用公告)"`
|
||
PopupTypeText string `json:"popup_type_text" description:"弹窗类型名称(中文)"`
|
||
Pages []string `json:"pages" enums:"home,asset_detail,package_purchase,asset_wallet_recharge" description:"命中页面集合 (home:首页, asset_detail:资产详情, package_purchase:套餐购买, asset_wallet_recharge:资产钱包充值)"`
|
||
ShopIDs []uint `json:"shop_ids" description:"店铺范围;空数组表示全量"`
|
||
DeviceTypes []string `json:"device_types" description:"设备类型范围;空数组表示全量"`
|
||
CardTypes []string `json:"card_types" enums:"CMCC,CUCC,CTCC,CBN" description:"卡类型范围 (CMCC:中国移动, CUCC:中国联通, CTCC:中国电信, CBN:中国广电);空数组表示全量"`
|
||
Priority int `json:"priority" description:"优先级,数值越大越优先"`
|
||
Frequency string `json:"frequency" enums:"once,daily" description:"投放频率 (once:每客户每配置版本仅一次, daily:每客户每配置版本每个上海自然日一次)"`
|
||
FrequencyText string `json:"frequency_text" description:"投放频率名称(中文)"`
|
||
Enabled bool `json:"enabled" description:"是否启用;停用后停止新投放,历史通知在展示期内仍可见"`
|
||
EnabledText string `json:"enabled_text" description:"启停状态名称(中文)"`
|
||
ActionType string `json:"action_type" enums:"package_purchase,asset_wallet_recharge" description:"受控动作 (package_purchase:套餐购买, asset_wallet_recharge:资产钱包充值);空值表示无受控动作"`
|
||
StartsAt time.Time `json:"starts_at" description:"生效开始时间(ISO 8601)"`
|
||
EndsAt time.Time `json:"ends_at" description:"生效结束时间(ISO 8601)"`
|
||
Version int64 `json:"version" description:"配置版本,每次更新递增;版本参与频率去重,旧版本通知保留原快照"`
|
||
CreatedAt time.Time `json:"created_at" description:"创建时间(ISO 8601)"`
|
||
UpdatedAt time.Time `json:"updated_at" description:"最近更新时间(ISO 8601);启停同样刷新该时间"`
|
||
Creator uint `json:"creator" description:"创建人账号ID"`
|
||
Updater uint `json:"updater" description:"最近更新人账号ID"`
|
||
}
|
||
|
||
// H5PopupConfigurationListRequest 是运营弹窗配置列表分页参数。
|
||
type H5PopupConfigurationListRequest struct {
|
||
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=100" minimum:"1" maximum:"100" description:"每页数量,默认 20,最大 100"`
|
||
Enabled *bool `json:"enabled" query:"enabled" description:"启停筛选;不传时查询全部"`
|
||
}
|
||
|
||
// H5PopupConfigurationListResponse 是运营弹窗配置分页结果。
|
||
type H5PopupConfigurationListResponse struct {
|
||
Items []H5PopupConfigurationResponse `json:"items" description:"运营弹窗配置列表"`
|
||
Total int64 `json:"total" description:"总数量"`
|
||
Page int `json:"page" description:"页码"`
|
||
Size int `json:"size" description:"每页数量"`
|
||
}
|
||
|
||
// PopupCandidateRequest 是当前客户查询弹窗候选的请求。
|
||
// 首页也必须先由客户选定当前资产,因此 identifier 在所有页面都是必填。
|
||
type PopupCandidateRequest struct {
|
||
Page string `json:"page" query:"page" validate:"required,oneof=home asset_detail package_purchase asset_wallet_recharge" required:"true" enum:"home,asset_detail,package_purchase,asset_wallet_recharge" description:"当前页面 (home:首页, asset_detail:资产详情, package_purchase:套餐购买, asset_wallet_recharge:资产钱包充值)"`
|
||
Identifier string `json:"identifier" query:"identifier" validate:"required,min=1,max=100" required:"true" minLength:"1" maxLength:"100" description:"当前资产标识符,卡支持 ICCID、接入号、虚拟号,设备支持虚拟号、IMEI、SN"`
|
||
}
|
||
|
||
// PopupCandidateResponse 是弹窗候选结果;candidate 为空表示当前页面与资产没有可投放弹窗。
|
||
type PopupCandidateResponse struct {
|
||
Candidate *PopupCandidateItem `json:"candidate,omitempty" description:"弹窗候选;为空表示当前页面与资产没有可投放弹窗"`
|
||
}
|
||
|
||
// PopupCandidateItem 是当次投放或复用的弹窗候选。
|
||
// 只返回类型、资产关联与受控动作,不返回任何 URL 或前端路由;前端按 action_type 白名单映射页面。
|
||
type PopupCandidateItem struct {
|
||
NotificationID uint `json:"notification_id" description:"投放或复用的站内通知ID;关闭或稍后处理时用它调用既有个人通知已读接口"`
|
||
PopupType string `json:"popup_type" enums:"risk_exchange,operation" description:"弹窗类型 (risk_exchange:风险换卡, operation:运营弹窗);风险换卡优先级固定高于运营弹窗"`
|
||
NotificationType string `json:"notification_type" enums:"h5.popup.risk_exchange,h5.popup.operation" description:"稳定通知类型 (h5.popup.risk_exchange:风险换卡弹窗, h5.popup.operation:运营弹窗)"`
|
||
Title string `json:"title" description:"弹窗标题,投放时冻结"`
|
||
Body string `json:"body" description:"弹窗正文,投放时冻结"`
|
||
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:资产钱包充值);为空表示无受控动作"`
|
||
ConfigID uint `json:"config_id" description:"运营弹窗配置ID;风险换卡弹窗固定为 0"`
|
||
ConfigVersion int64 `json:"config_version" description:"投放时的配置版本;风险换卡弹窗固定为 0"`
|
||
ExpiresAt *time.Time `json:"expires_at,omitempty" description:"展示截止时间(ISO 8601),自投放时间起 90 天"`
|
||
CreatedAt time.Time `json:"created_at" description:"投放时间(ISO 8601)"`
|
||
}
|
||
|
||
// ClientRiskExchangeAddressParams 是风险换卡地址提交的路径参数与请求体。
|
||
// 地址字段沿用既有换货地址字段与长度校验,不额外拆分省市区。
|
||
type ClientRiskExchangeAddressParams struct {
|
||
AssetID uint `json:"asset_id" path:"asset_id" required:"true" description:"待换卡资产ID(物联网卡数字ID)"`
|
||
ClientShippingInfoRequest
|
||
}
|
||
|
||
// ClientRiskExchangeResponse 是风险换卡地址提交结果。
|
||
// 重复提交返回首次创建的换货单与首次地址,不覆盖既有地址。
|
||
type ClientRiskExchangeResponse struct {
|
||
ID uint `json:"id" description:"物流换货单ID"`
|
||
ExchangeNo string `json:"exchange_no" description:"换货单号"`
|
||
Status int `json:"status" description:"换货状态 (2:待发货)"`
|
||
StatusName string `json:"status_name" description:"换货状态名称(中文)"`
|
||
FlowType string `json:"flow_type" description:"换货流程类型 (shipping:物流换货)"`
|
||
OldAssetType string `json:"old_asset_type" description:"旧资产类型 (iot_card:物联网卡)"`
|
||
OldAssetID uint `json:"old_asset_id" description:"旧资产ID"`
|
||
OldAssetIdentifier string `json:"old_asset_identifier" description:"旧资产权威快照,卡为完整 ICCID"`
|
||
RecipientName string `json:"recipient_name" description:"收件人姓名,首次提交后锁定"`
|
||
RecipientPhone string `json:"recipient_phone" description:"收件人电话,首次提交后锁定"`
|
||
RecipientAddress string `json:"recipient_address" description:"收货地址,首次提交后锁定,客户不可修改"`
|
||
MigrateData bool `json:"migrate_data" description:"是否执行全量迁移;风险换卡固定 false,发货选新资产时仍由后台按既有流程决定"`
|
||
MigrationStatus string `json:"migration_status" enums:"not_migrated,pending,migrated,failed" description:"业务数据迁移状态 (not_migrated:不迁移, pending:待迁移, migrated:已迁移, failed:迁移失败);迁移结果以本字段为准"`
|
||
MigrationStatusName string `json:"migration_status_name" description:"业务数据迁移状态名称(中文)"`
|
||
ExchangeReason string `json:"exchange_reason" description:"换货原因"`
|
||
CreatedAt time.Time `json:"created_at" description:"创建时间(ISO 8601)"`
|
||
}
|