package vendor import ( "encoding/json" "with_you/internal/config" ) // resolveChannelID 按场景选择 channel_id:厂商专属值优先,空则回退到全局默认 // scene 为 SceneSystem 时取 system 配置,其余取 chat 配置 func resolveChannelID(scene, vendorSys, vendorChat, defaultSys, defaultChat string) string { if scene == SceneSystem { if vendorSys != "" { return vendorSys } return defaultSys } if vendorChat != "" { return vendorChat } return defaultChat } // channelOnlyMap 仅 channel_id 厂商的通用转换逻辑(厂商空则回退全局默认) // 最终 channel_id 为空时返回 nil(不下发该厂商) func channelOnlyMap(scene, vendorSys, vendorChat, defaultSys, defaultChat string) map[string]any { cid := resolveChannelID(scene, vendorSys, vendorChat, defaultSys, defaultChat) if cid == "" { return nil } return map[string]any{"channel_id": cid} } // huaweiConverter 华为厂商转换器(仅 channel_id) type huaweiConverter struct{} func (huaweiConverter) VendorName() string { return "huawei" } func (huaweiConverter) Convert(params MessageParams, cfg config.ChannelConfig) map[string]any { return channelOnlyMap(params.Scene, cfg.Vendor.Huawei.System, cfg.Vendor.Huawei.Chat, cfg.System, cfg.Chat) } // vivoConverter VIVO 厂商转换器 // channel_id + category(厂商消息场景标识) // classification=1 时 category 必须为系统消息类,不携带 category 会默认按运营消息下发受频控限制 type vivoConverter struct{} func (vivoConverter) VendorName() string { return "vivo" } func (vivoConverter) Convert(params MessageParams, cfg config.ChannelConfig) map[string]any { v := cfg.Vendor.VIVO cid := resolveChannelID(params.Scene, v.System, v.Chat, cfg.System, cfg.Chat) category := v.VivoChatCategory if params.Scene == SceneSystem { category = v.VivoSystemCategory } if cid == "" && category == "" { return nil } m := map[string]any{} if cid != "" { m["channel_id"] = cid } if category != "" { m["category"] = category } return m } // meizuConverter 魅族厂商转换器(仅 channel_id) type meizuConverter struct{} func (meizuConverter) VendorName() string { return "meizu" } func (meizuConverter) Convert(params MessageParams, cfg config.ChannelConfig) map[string]any { return channelOnlyMap(params.Scene, cfg.Vendor.Meizu.System, cfg.Vendor.Meizu.Chat, cfg.System, cfg.Chat) } // honorConverter 荣耀厂商转换器 // channel_id + importance(通知栏消息智能分类) // importance 取值:"NORMAL"=服务与通讯,"LOW"=资讯营销 // 注:classification 优先级更高,会覆盖 importance 设置的值 type honorConverter struct{} func (honorConverter) VendorName() string { return "honor" } func (honorConverter) Convert(params MessageParams, cfg config.ChannelConfig) map[string]any { h := cfg.Vendor.Honor cid := resolveChannelID(params.Scene, h.System, h.Chat, cfg.System, cfg.Chat) importance := h.HonorChatImportance if params.Scene == SceneSystem { importance = h.HonorSystemImportance } if cid == "" && importance == "" { return nil } m := map[string]any{} if cid != "" { m["channel_id"] = cid } if importance != "" { m["importance"] = importance } return m } // fcmConverter FCM 厂商转换器(仅 channel_id) type fcmConverter struct{} func (fcmConverter) VendorName() string { return "fcm" } func (fcmConverter) Convert(params MessageParams, cfg config.ChannelConfig) map[string]any { return channelOnlyMap(params.Scene, cfg.Vendor.FCM.System, cfg.Vendor.FCM.Chat, cfg.System, cfg.Chat) } // xiaomiConverter 小米厂商转换器 // 配置 mi_template_id 时,私信消息下发时携带 channel_id 及 mi_template_id + mi_template_param type xiaomiConverter struct{} func (xiaomiConverter) VendorName() string { return "xiaomi" } func (xiaomiConverter) Convert(params MessageParams, cfg config.ChannelConfig) map[string]any { x := cfg.Vendor.Xiaomi cid := resolveChannelID(params.Scene, x.System, x.Chat, cfg.System, cfg.Chat) // 小米模板按场景选择 templateID := x.MiChatTemplateID if params.Scene == SceneSystem { templateID = x.MiSystemTemplateID } // 最终 channel_id 与模板均未配置则跳过 if cid == "" && templateID == "" { return nil } m := map[string]any{} if cid != "" { m["channel_id"] = cid } if templateID != "" { m["mi_template_id"] = templateID // mi_template_param 为模板参数的 JSON 字符串 m["mi_template_param"] = buildMiTemplateParam(params) } return m } // buildMiTemplateParam 生成小米消息模板参数 JSON 字符串 // 占位符严格匹配小米模板定义的 keywords: // - 私聊模板(M10289 好友聊天): keywords1=title, keywords2=发送者, keywords3=内容 // - 系统模板(P10761 系统消息): keywords1=标题, keywords2=内容 func buildMiTemplateParam(params MessageParams) string { var param map[string]any if params.Scene == SceneSystem { param = map[string]any{ "keywords1": params.Title, "keywords2": params.Body, } } else { param = map[string]any{ "keywords1": params.Title, "keywords2": params.SenderName, "keywords3": params.Body, } } b, err := json.Marshal(param) if err != nil { return "{}" } return string(b) } // oppoConverter OPPO 厂商转换器 // 配置 private_msg_template_id 时,私信消息下发时携带 private_msg_template_id + private_title_parameters + private_content_parameters type oppoConverter struct{} func (oppoConverter) VendorName() string { return "oppo" } func (oppoConverter) Convert(params MessageParams, cfg config.ChannelConfig) map[string]any { o := cfg.Vendor.OPPO cid := resolveChannelID(params.Scene, o.System, o.Chat, cfg.System, cfg.Chat) // OPPO 私信模板按场景选择 templateID := o.OppoChatPrivateTemplateID category := o.OppoChatCategory notifyLevel := o.OppoChatNotifyLevel if params.Scene == SceneSystem { templateID = o.OppoSystemPrivateTemplateID category = o.OppoSystemCategory notifyLevel = o.OppoSystemNotifyLevel } if cid == "" && templateID == "" && category == "" && notifyLevel == 0 { return nil } m := map[string]any{} if cid != "" { m["channel_id"] = cid } if templateID != "" { m["private_msg_template_id"] = templateID // private_title_parameters / private_content_parameters 为 JSONObject m["private_title_parameters"] = map[string]any{ "title": params.Title, } m["private_content_parameters"] = map[string]any{ "content": params.Body, "sender": params.SenderName, } } // OPPO 2024.11.20 新规:category 消息场景标识,notify_level 提醒等级 // 文档约束:使用 notify_level 时 category 必传,否则 OPPO 校验失败 // 这里做保护:notify_level 非零但 category 为空时跳过 notify_level if category != "" { m["category"] = category if notifyLevel != 0 { m["notify_level"] = notifyLevel } } return m }