package welcome import ( "context" "fmt" "time" "cellbot/internal/engine" "cellbot/internal/protocol" "cellbot/pkg/utils" "go.uber.org/zap" ) func init() { // 监听群成员增加通知事件 engine.OnNotice("group_increase"). Priority(50). // 设置较高优先级,确保及时响应 Handle(handleWelcomeEvent) } // handleWelcomeEvent 处理群成员加入欢迎事件 func handleWelcomeEvent(ctx context.Context, event protocol.Event, botManager *protocol.BotManager, logger *zap.Logger) error { logger.Info("Welcome event received", zap.String("event_type", string(event.GetType())), zap.String("detail_type", event.GetDetailType()), zap.String("sub_type", event.GetSubType()), zap.String("self_id", event.GetSelfID())) // 注意:中间件已经过滤了 detail_type,这里可以简化检查 data := event.GetData() logger.Debug("Event data", zap.Any("data", data)) // 获取群ID和用户ID groupID, ok := data["group_id"] if !ok { logger.Warn("Missing group_id in event data") return nil } userID, ok := data["user_id"] if !ok { logger.Warn("Missing user_id in event data") return nil } logger.Info("Processing welcome event", zap.Any("group_id", groupID), zap.Any("user_id", userID)) // 获取操作者ID(邀请者或审批者) var operatorID interface{} if opID, exists := data["operator_id"]; exists { operatorID = opID } // 获取子类型(approve: 管理员同意, invite: 邀请) subType := event.GetSubType() // 获取 bot 实例 selfID := event.GetSelfID() bot, ok := botManager.Get(selfID) if !ok { bots := botManager.GetAll() if len(bots) == 0 { logger.Error("No bot instance available") return nil } bot = bots[0] } // 构建欢迎消息链(使用HTML模板渲染图片) logger.Info("Building welcome message", zap.Any("user_id", userID), zap.Any("operator_id", operatorID), zap.String("sub_type", subType)) welcomeChain, err := buildWelcomeMessage(ctx, userID, operatorID, subType, logger) if err != nil { logger.Error("Failed to build welcome message", zap.Any("user_id", userID), zap.Any("operator_id", operatorID), zap.String("sub_type", subType), zap.Error(err)) return err } logger.Info("Welcome message built successfully", zap.Int("chain_length", len(welcomeChain))) // 发送群消息 logger.Info("Sending welcome message", zap.Any("group_id", groupID), zap.Any("user_id", userID)) action := &protocol.BaseAction{ Type: protocol.ActionTypeSendGroupMessage, Params: map[string]interface{}{ "group_id": groupID, "message": welcomeChain, }, } result, err := bot.SendAction(ctx, action) if err != nil { logger.Error("Failed to send welcome message", zap.Any("group_id", groupID), zap.Any("user_id", userID), zap.Any("action_type", action.Type), zap.Error(err)) return err } logger.Info("Welcome message sent successfully", zap.Any("group_id", groupID), zap.Any("user_id", userID), zap.Any("result", result)) logger.Info("Welcome message sent", zap.Any("group_id", groupID), zap.Any("user_id", userID), zap.String("sub_type", subType)) return nil } // welcomeTemplate HTML欢迎消息模板 const welcomeTemplate = `
🎉
欢迎加入!
Welcome to the Group
{{if .JoinType}}
{{.JoinType}}
{{end}}
💡 温馨提示
  • 请遵守群规,文明交流
  • 如有问题可以@管理员
  • 发送 /help 查看帮助
` // buildWelcomeMessage 构建欢迎消息链(使用HTML模板渲染图片) func buildWelcomeMessage(ctx context.Context, userID, operatorID interface{}, subType string, logger *zap.Logger) (protocol.MessageChain, error) { logger.Debug("Starting to build welcome message", zap.Any("user_id", userID), zap.Any("operator_id", operatorID), zap.String("sub_type", subType)) // 准备模板数据 data := map[string]interface{}{ "UserID": fmt.Sprintf("%v", userID), } logger.Debug("Template data prepared", zap.Any("data", data)) // 根据加入方式设置不同的信息 switch subType { case "approve": data["JoinType"] = "✅ 管理员审批通过" if operatorID != nil { data["OperatorID"] = fmt.Sprintf("%v", operatorID) data["OperatorLabel"] = "审批管理员" } case "invite": data["JoinType"] = "👥 被邀请加入" if operatorID != nil { data["OperatorID"] = fmt.Sprintf("%v", operatorID) data["OperatorLabel"] = "邀请人" } default: data["JoinType"] = "🎊 加入群聊" } // 配置截图选项 opts := &utils.ScreenshotOptions{ Width: 1200, // 增加宽度,确保内容有足够空间 Height: 800, // 增加高度,确保内容完整显示 Timeout: 60 * time.Second, // 增加超时时间到60秒 WaitTime: 3 * time.Second, // 增加等待时间,确保页面完全加载 FullPage: false, Quality: 90, Logger: logger, } // 渲染模板并截图 logger.Info("Rendering template and taking screenshot", zap.Int("width", opts.Width), zap.Int("height", opts.Height), zap.Duration("timeout", opts.Timeout)) chain, err := utils.ScreenshotTemplateToMessageChain(ctx, welcomeTemplate, data, opts) if err != nil { logger.Error("Failed to render welcome template", zap.Any("data", data), zap.Error(err)) return nil, fmt.Errorf("failed to render welcome template: %w", err) } logger.Info("Template rendered and screenshot taken successfully", zap.Int("chain_length", len(chain))) return chain, nil }