2026-06-17 20:41:55 +08:00
|
|
|
|
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)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-18 19:41:32 +08:00
|
|
|
|
// vivoConverter VIVO 厂商转换器
|
|
|
|
|
|
// channel_id + category(厂商消息场景标识)
|
|
|
|
|
|
// classification=1 时 category 必须为系统消息类,不携带 category 会默认按运营消息下发受频控限制
|
2026-06-17 20:41:55 +08:00
|
|
|
|
type vivoConverter struct{}
|
|
|
|
|
|
|
|
|
|
|
|
func (vivoConverter) VendorName() string { return "vivo" }
|
|
|
|
|
|
func (vivoConverter) Convert(params MessageParams, cfg config.ChannelConfig) map[string]any {
|
2026-06-18 19:41:32 +08:00
|
|
|
|
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
|
2026-06-17 20:41:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-18 19:41:32 +08:00
|
|
|
|
// honorConverter 荣耀厂商转换器
|
|
|
|
|
|
// channel_id + importance(通知栏消息智能分类)
|
|
|
|
|
|
// importance 取值:"NORMAL"=服务与通讯,"LOW"=资讯营销
|
|
|
|
|
|
// 注:classification 优先级更高,会覆盖 importance 设置的值
|
2026-06-17 20:41:55 +08:00
|
|
|
|
type honorConverter struct{}
|
|
|
|
|
|
|
|
|
|
|
|
func (honorConverter) VendorName() string { return "honor" }
|
|
|
|
|
|
func (honorConverter) Convert(params MessageParams, cfg config.ChannelConfig) map[string]any {
|
2026-06-18 19:41:32 +08:00
|
|
|
|
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
|
2026-06-17 20:41:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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 字符串
|
2026-06-18 19:41:32 +08:00
|
|
|
|
// 占位符严格匹配小米模板定义的 keywords:
|
|
|
|
|
|
// - 私聊模板(M10289 好友聊天): keywords1=title, keywords2=发送者, keywords3=内容
|
|
|
|
|
|
// - 系统模板(P10761 系统消息): keywords1=标题, keywords2=内容
|
2026-06-17 20:41:55 +08:00
|
|
|
|
func buildMiTemplateParam(params MessageParams) string {
|
2026-06-18 19:41:32 +08:00
|
|
|
|
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,
|
|
|
|
|
|
}
|
2026-06-17 20:41:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
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
|
2026-06-18 19:41:32 +08:00
|
|
|
|
category := o.OppoChatCategory
|
|
|
|
|
|
notifyLevel := o.OppoChatNotifyLevel
|
2026-06-17 20:41:55 +08:00
|
|
|
|
if params.Scene == SceneSystem {
|
|
|
|
|
|
templateID = o.OppoSystemPrivateTemplateID
|
2026-06-18 19:41:32 +08:00
|
|
|
|
category = o.OppoSystemCategory
|
|
|
|
|
|
notifyLevel = o.OppoSystemNotifyLevel
|
2026-06-17 20:41:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-18 19:41:32 +08:00
|
|
|
|
if cid == "" && templateID == "" && category == "" && notifyLevel == 0 {
|
2026-06-17 20:41:55 +08:00
|
|
|
|
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,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-06-18 19:41:32 +08:00
|
|
|
|
// 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
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-06-17 20:41:55 +08:00
|
|
|
|
return m
|
|
|
|
|
|
}
|