1. 增加钉钉IM客户端,增加创建并投放卡片方法 2.规范化多处配置获取代码 3.增加获取入群二维码链接方法 4.调整加群流程为 确认加群-创建群聊-将机器人添加到新群-获取新群分享链接-点击跳转至新群

This commit is contained in:
fuzhongyun 2026-01-21 18:43:01 +08:00
parent a0b76f1581
commit 534da15898
12 changed files with 304 additions and 115 deletions

View File

@ -309,7 +309,7 @@ func (r *Handle) getUserDingtalkUnionId(ctx context.Context, accessToken, sessio
creatorName := session.UserName
// 获取创建者uid 用户名 -> dingtalk uid
creatorId, err := r.dingtalkContactClient.SearchUserOne(accessToken, creatorName)
creatorId, err := r.dingtalkContactClient.SearchUserOne(dingtalk.AppKey{AccessToken: accessToken}, creatorName)
if err != nil {
log.Warnf("search dingtalk user one failed: %v", err)
return

View File

@ -265,7 +265,7 @@ func (g *GroupConfigBiz) handleMatch(ctx context.Context, rec *entitys.Recognize
case constants.TaskTypeCozeWorkflow:
return g.handleCozeWorkflow(ctx, rec, pointTask)
case constants.TaskTypeKnowle: // 知识库V2版本
return g.handleKnowledgeV2(ctx, rec, pointTask)
return g.handleKnowledgeV2(ctx, rec, groupConfig)
// return g.handleKnowledgeV3(ctx, rec, pointTask)
default:
return g.otherTask(ctx, rec)
@ -473,7 +473,7 @@ func (g *GroupConfigBiz) GetReportCache(ctx context.Context, day time.Time, tota
}
// handleKnowledgeV2 处理知识库V2版本
func (g *GroupConfigBiz) handleKnowledgeV2(ctx context.Context, rec *entitys.Recognize, pointTask *model.AiBotTool) (err error) {
func (g *GroupConfigBiz) handleKnowledgeV2(ctx context.Context, rec *entitys.Recognize, groupConfig *model.AiBotGroupConfig) (err error) {
req := l_request.Request{
Method: "POST",
Url: "http://127.0.0.1:9600/query",
@ -499,12 +499,24 @@ func (g *GroupConfigBiz) handleKnowledgeV2(ctx context.Context, rec *entitys.Rec
return
}
// var DingtalkGroupCaseOwner = map[string][]string{
// "cidwP24PLZhLVOS2dVIkEawLw==": {"付仲云", "贺泽琨", "任志远"},
// }
// 未检索到匹配信息,询问是否拉群
if !isRetrieved {
// 获取群问题处理人
type issueOwnerType struct {
UserId string `json:"userid"`
Name string `json:"name"`
}
var issueOwner []issueOwnerType
if err = json.Unmarshal([]byte(groupConfig.IssueOwner), &issueOwner); err != nil {
return fmt.Errorf("解析群问题处理人失败err: %v", err)
}
// 合并所有name
var userNames []string
for _, owner := range issueOwner {
userNames = append(userNames, "@"+owner.Name)
}
issueOwnerStr := strings.Join(userNames, "、")
// 构建卡片 OutTrackId
outTrackId := constants.BuildCardOutTrackId("cidwP24PLZhLVOS2dVIkEawLw==", "ding5wwvnf9hxeyjau7t")
@ -519,7 +531,7 @@ func (g *GroupConfigBiz) handleKnowledgeV2(ctx context.Context, rec *entitys.Rec
CardData: &card_1_0.CreateAndDeliverRequestCardData{
CardParamMap: map[string]*string{
"title": tea.String("群创建提醒"),
"content": tea.String("**确认创建群聊?**\n\n将邀请以下成员加入群聊\n\n@张三、@李四"),
"content": tea.String(fmt.Sprintf("**确认创建群聊?**\n\n将邀请以下成员加入群聊\n\n%s", issueOwnerStr)),
"remark": tea.String("注:如若无需,忽略即可"),
"button_left": tea.String("点击进群"),
"button_left_link": tea.String(""),

View File

@ -1,7 +1,6 @@
package dingtalk
import (
"ai_scheduler/internal/config"
errorcode "ai_scheduler/internal/data/error"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
@ -11,30 +10,27 @@ import (
)
type CardClient struct {
config *config.Config
cli *card.Client
oauth2Client *Oauth2Client
}
func NewCardClient(config *config.Config, oauth2Client *Oauth2Client) (*CardClient, error) {
func NewCardClient(oauth2Client *Oauth2Client) (*CardClient, error) {
cfg := &openapi.Config{
AccessKeyId: tea.String(config.Tools.DingTalkBot.APIKey),
AccessKeySecret: tea.String(config.Tools.DingTalkBot.APISecret),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
}
c, err := card.NewClient(cfg)
if err != nil {
return nil, err
}
return &CardClient{config: config, cli: c, oauth2Client: oauth2Client}, nil
return &CardClient{cli: c, oauth2Client: oauth2Client}, nil
}
// 创建并投放卡片
func (c *CardClient) CreateAndDeliver(req AppKey, cardData *card.CreateAndDeliverRequest) (bool, error) {
func (c *CardClient) CreateAndDeliver(appKey AppKey, cardData *card.CreateAndDeliverRequest) (bool, error) {
// 获取token
accessToken, err := c.oauth2Client.GetAccessToken(req)
accessToken, err := c.oauth2Client.GetAccessToken(appKey)
if err != nil {
return false, err
}
@ -60,9 +56,9 @@ func (c *CardClient) CreateAndDeliver(req AppKey, cardData *card.CreateAndDelive
}
// 更新卡片
func (c *CardClient) UpdateCard(req AppKey, cardData *card.UpdateCardRequest) (bool, error) {
func (c *CardClient) UpdateCard(appKey AppKey, cardData *card.UpdateCardRequest) (bool, error) {
// 获取token
accessToken, err := c.oauth2Client.GetAccessToken(req)
accessToken, err := c.oauth2Client.GetAccessToken(appKey)
if err != nil {
return false, err
}

View File

@ -1,7 +1,6 @@
package dingtalk
import (
"ai_scheduler/internal/config"
errorcode "ai_scheduler/internal/data/error"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
@ -11,22 +10,20 @@ import (
)
type ContactClient struct {
config *config.Config
cli *contact.Client
cli *contact.Client
oauth2Client *Oauth2Client
}
func NewContactClient(config *config.Config) (*ContactClient, error) {
func NewContactClient(oauth2Client *Oauth2Client) (*ContactClient, error) {
cfg := &openapi.Config{
AccessKeyId: tea.String(config.Tools.DingTalkBot.APIKey),
AccessKeySecret: tea.String(config.Tools.DingTalkBot.APISecret),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
}
c, err := contact.NewClient(cfg)
if err != nil {
return nil, err
}
return &ContactClient{config: config, cli: c}, nil
return &ContactClient{cli: c, oauth2Client: oauth2Client}, nil
}
type SearchUserReq struct {
@ -40,15 +37,23 @@ type SearchUserResp struct {
Body interface{}
}
func (c *ContactClient) SearchUserOne(accessToken string, name string) (string, error) {
headers := &contact.SearchUserHeaders{}
headers.XAcsDingtalkAccessToken = tea.String(accessToken)
resp, err := c.cli.SearchUserWithOptions(&contact.SearchUserRequest{
FullMatchField: tea.Int32(1),
QueryWord: tea.String(name),
Offset: tea.Int32(0),
Size: tea.Int32(1),
}, headers, &util.RuntimeOptions{})
func (c *ContactClient) SearchUserOne(appKey AppKey, name string) (string, error) {
// 获取token
accessToken, err := c.oauth2Client.GetAccessToken(appKey)
if err != nil {
return "", err
}
resp, err := c.cli.SearchUserWithOptions(
&contact.SearchUserRequest{
FullMatchField: tea.Int32(1),
QueryWord: tea.String(name),
Offset: tea.Int32(0),
Size: tea.Int32(1),
},
&contact.SearchUserHeaders{XAcsDingtalkAccessToken: tea.String(accessToken)},
&util.RuntimeOptions{},
)
if err != nil {
return "", err
}

View File

@ -0,0 +1,53 @@
package dingtalk
import (
errorcode "ai_scheduler/internal/data/error"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
im "github.com/alibabacloud-go/dingtalk/im_1_0"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
)
type ImClient struct {
cli *im.Client
oauth2Client *Oauth2Client
}
func NewImClient(oauth2Client *Oauth2Client) (*ImClient, error) {
cfg := &openapi.Config{
Protocol: tea.String("https"),
RegionId: tea.String("central"),
}
c, err := im.NewClient(cfg)
if err != nil {
return nil, err
}
return &ImClient{cli: c, oauth2Client: oauth2Client}, nil
}
// 创建并投放卡片
func (c *ImClient) AddRobotToConversation(appKey AppKey, imData *im.AddRobotToConversationRequest) (string, error) {
// 获取token
accessToken, err := c.oauth2Client.GetAccessToken(appKey)
if err != nil {
return "", err
}
// 调用API
resp, err := c.cli.AddRobotToConversationWithOptions(
imData,
&im.AddRobotToConversationHeaders{XAcsDingtalkAccessToken: tea.String(accessToken)},
&util.RuntimeOptions{},
)
if err != nil {
return "", err
}
if resp.Body == nil {
return "", errorcode.ParamErrf("empty response body")
}
return *resp.Body.ChatBotUserId, nil
}

View File

@ -1,7 +1,6 @@
package dingtalk
import (
"ai_scheduler/internal/config"
errorcode "ai_scheduler/internal/data/error"
"encoding/json"
"time"
@ -13,22 +12,20 @@ import (
)
type NotableClient struct {
config *config.Config
cli *notable.Client
cli *notable.Client
oauth2Client *Oauth2Client
}
func NewNotableClient(config *config.Config) (*NotableClient, error) {
func NewNotableClient(oauth2Client *Oauth2Client) (*NotableClient, error) {
cfg := &openapi.Config{
AccessKeyId: tea.String(config.Tools.DingTalkBot.APIKey),
AccessKeySecret: tea.String(config.Tools.DingTalkBot.APISecret),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
}
c, err := notable.NewClient(cfg)
if err != nil {
return nil, err
}
return &NotableClient{config: config, cli: c}, nil
return &NotableClient{cli: c, oauth2Client: oauth2Client}, nil
}
type UpdateRecordReq struct {
@ -43,9 +40,13 @@ type UpdateRecordsserResp struct {
Body interface{}
}
func (c *NotableClient) UpdateRecord(accessToken string, req *UpdateRecordReq) (bool, error) {
headers := &notable.UpdateRecordsHeaders{}
headers.XAcsDingtalkAccessToken = tea.String(accessToken)
func (c *NotableClient) UpdateRecord(appKey AppKey, req *UpdateRecordReq) (bool, error) {
// 获取token
accessToken, err := c.oauth2Client.GetAccessToken(appKey)
if err != nil {
return false, err
}
resp, err := c.cli.UpdateRecordsWithOptions(
tea.String(req.BaseId),
tea.String(req.SheetId),
@ -63,7 +64,10 @@ func (c *NotableClient) UpdateRecord(accessToken string, req *UpdateRecordReq) (
Id: tea.String(req.RecordId),
},
},
}, headers, &util.RuntimeOptions{})
},
&notable.UpdateRecordsHeaders{XAcsDingtalkAccessToken: tea.String(accessToken)},
&util.RuntimeOptions{},
)
if err != nil {
return false, err
}

View File

@ -1,7 +1,6 @@
package dingtalk
import (
"ai_scheduler/internal/config"
errorcode "ai_scheduler/internal/data/error"
"ai_scheduler/utils"
"context"
@ -15,32 +14,35 @@ import (
)
type Oauth2Client struct {
config *config.Config
cli *oauth2.Client
redisCli *redis.Client
}
func NewOauth2Client(config *config.Config, rds *utils.Rdb) (*Oauth2Client, error) {
func NewOauth2Client(rds *utils.Rdb) (*Oauth2Client, error) {
cfg := &openapi.Config{
AccessKeyId: tea.String(config.Tools.DingTalkBot.APIKey),
AccessKeySecret: tea.String(config.Tools.DingTalkBot.APISecret),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
}
c, err := oauth2.NewClient(cfg)
if err != nil {
return nil, err
}
return &Oauth2Client{config: config, cli: c, redisCli: rds.Rdb}, nil
return &Oauth2Client{cli: c, redisCli: rds.Rdb}, nil
}
type AppKey struct {
AppKey string `json:"appKey"`
AppSecret string `json:"appSecret"`
AppKey string `json:"appKey"`
AppSecret string `json:"appSecret"`
AccessToken string `json:"accessToken"`
}
// GetAccessToken 获取access token
func (c *Oauth2Client) GetAccessToken(req AppKey) (string, error) {
// 兼容直接传入 access token 场景
if req.AccessToken != "" {
return req.AccessToken, nil
}
// 取cache
ctx := context.Background()
accessToken, err := c.redisCli.Get(ctx, fmt.Sprintf("dingtalk:oauth2:%s:access_token", req.AppKey)).Result()

View File

@ -113,7 +113,7 @@ func (c *OldClient) GetAccessToken() (string, error) {
}
// CreateInternalGroupConversation 创建企业内部群聊
func (c *OldClient) CreateInternalGroupConversation(ctx context.Context, groupName string, userIds []string) (string, error) {
func (c *OldClient) CreateInternalGroupConversation(ctx context.Context, groupName string, userIds []string) (chatId, openConversationId string, err error) {
body := struct {
Name string `json:"name"`
Owner string `json:"owner"`
@ -130,9 +130,10 @@ func (c *OldClient) CreateInternalGroupConversation(ctx context.Context, groupNa
UserIds: userIds,
}
b, _ := json.Marshal(body)
res, err := c.do(ctx, http.MethodPost, "/chat/create", b)
var res []byte
res, err = c.do(ctx, http.MethodPost, "/chat/create", b)
if err != nil {
return "", err
return
}
var resp struct {
Code int `json:"errcode"`
@ -141,11 +142,37 @@ func (c *OldClient) CreateInternalGroupConversation(ctx context.Context, groupNa
OpenConversationId string `json:"openConversationId"`
ConversationTag int `json:"conversationTag"`
}
if err = json.Unmarshal(res, &resp); err != nil {
return
}
if resp.Code != 0 {
return "", "", errors.New(resp.Msg)
}
return resp.ChatId, resp.OpenConversationId, nil
}
// 获取入群二维码链接
func (c *OldClient) GetJoinGroupQrcode(ctx context.Context, chatId, userId string) (string, error) {
body := struct {
ChatId string `json:"chatid"`
UserId string `json:"userid"`
}{ChatId: chatId, UserId: userId}
b, _ := json.Marshal(body)
res, err := c.do(ctx, http.MethodPost, "/topapi/chat/qrcode/get", b)
if err != nil {
return "", err
}
var resp struct {
Code int `json:"errcode"`
Msg string `json:"errmsg"`
Result string `json:"result"`
}
if err := json.Unmarshal(res, &resp); err != nil {
return "", err
}
if resp.Code != 0 {
return "", errors.New(resp.Msg)
}
return resp.OpenConversationId, nil
return resp.Result, nil
}

View File

@ -1,7 +1,6 @@
package dingtalk
import (
"ai_scheduler/internal/config"
errorcode "ai_scheduler/internal/data/error"
"encoding/json"
@ -12,22 +11,19 @@ import (
)
type RobotClient struct {
config *config.Config
cli *robot.Client
cli *robot.Client
}
func NewRobotClient(config *config.Config) (*RobotClient, error) {
func NewRobotClient() (*RobotClient, error) {
cfg := &openapi.Config{
AccessKeyId: tea.String(config.Tools.DingTalkBot.APIKey),
AccessKeySecret: tea.String(config.Tools.DingTalkBot.APISecret),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
Protocol: tea.String("https"),
RegionId: tea.String("central"),
}
c, err := robot.NewClient(cfg)
if err != nil {
return nil, err
}
return &RobotClient{config: config, cli: c}, nil
return &RobotClient{cli: c}, nil
}
type SendGroupMessagesReq struct {
@ -37,17 +33,19 @@ type SendGroupMessagesReq struct {
RobotCode string
}
func (c *RobotClient) SendGroupMessages(accessToken string, req *SendGroupMessagesReq) (string, error) {
headers := &robot.OrgGroupSendHeaders{}
headers.XAcsDingtalkAccessToken = tea.String(accessToken)
func (c *RobotClient) SendGroupMessages(appKey AppKey, req *SendGroupMessagesReq) (string, error) {
msgParamBytes, _ := json.Marshal(req.MsgParam)
msgParamJson := string(msgParamBytes)
resp, err := c.cli.OrgGroupSendWithOptions(&robot.OrgGroupSendRequest{
MsgKey: tea.String(req.MsgKey),
MsgParam: tea.String(msgParamJson),
OpenConversationId: tea.String(req.OpenConversationId),
RobotCode: tea.String(req.RobotCode),
}, headers, &util.RuntimeOptions{})
resp, err := c.cli.OrgGroupSendWithOptions(
&robot.OrgGroupSendRequest{
MsgKey: tea.String(req.MsgKey),
MsgParam: tea.String(msgParamJson),
OpenConversationId: tea.String(req.OpenConversationId),
RobotCode: tea.String(req.RobotCode),
},
&robot.OrgGroupSendHeaders{XAcsDingtalkAccessToken: tea.String(appKey.AccessToken)},
&util.RuntimeOptions{},
)
if err != nil {
return "", err
}

View File

@ -24,6 +24,7 @@ var ProviderSetClient = wire.NewSet(
// dingtalk.NewRobotClient,
dingtalk.NewOauth2Client,
dingtalk.NewCardClient,
dingtalk.NewImClient,
utils_oss.NewClient,
lsxd.NewLogin,

View File

@ -270,7 +270,7 @@ func (s *CallbackService) handleBugOptimizationSubmitUpdate(ctx context.Context,
// 获取创建者uid
accessToken, _ := s.dingtalkOldClient.GetAccessToken()
creatorId, err := s.dingtalkContactClient.SearchUserOne(accessToken, data.Creator)
creatorId, err := s.dingtalkContactClient.SearchUserOne(dingtalk.AppKey{AccessToken: accessToken}, data.Creator)
if err != nil {
return "", errorcode.ParamErrf("invalid data type: %v", err)
}
@ -286,7 +286,7 @@ func (s *CallbackService) handleBugOptimizationSubmitUpdate(ctx context.Context,
unionId := userDetails.UnionID
// 更新记录
ok, err := s.dingtalkNotableClient.UpdateRecord(accessToken, &dingtalk.UpdateRecordReq{
ok, err := s.dingtalkNotableClient.UpdateRecord(dingtalk.AppKey{AccessToken: accessToken}, &dingtalk.UpdateRecordReq{
BaseId: data.BaseId,
SheetId: data.SheetId,
RecordId: data.RecordId,

View File

@ -10,12 +10,16 @@ import (
"ai_scheduler/internal/pkg/dingtalk"
"context"
"encoding/json"
"fmt"
"log"
"sync"
"time"
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/card"
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
"github.com/alibabacloud-go/dingtalk/card_1_0"
"github.com/alibabacloud-go/dingtalk/im_1_0"
"github.com/alibabacloud-go/tea/tea"
"golang.org/x/sync/errgroup"
"xorm.io/builder"
)
@ -25,8 +29,10 @@ type DingBotService struct {
dingTalkBotBiz *biz.DingTalkBotBiz
dingTalkOld *dingtalk.OldClient
dingtalkCardClient *dingtalk.CardClient
dingtalkImClient *dingtalk.ImClient
botGroupConfigImpl *impl.BotGroupConfigImpl
botGroupImpl *impl.BotGroupImpl
botConfigImpl *impl.BotConfigImpl
}
func NewDingBotService(
@ -34,16 +40,20 @@ func NewDingBotService(
dingTalkBotBiz *biz.DingTalkBotBiz,
dingTalkOld *dingtalk.OldClient,
dingtalkCardClient *dingtalk.CardClient,
dingtalkImClient *dingtalk.ImClient,
botGroupConfigImpl *impl.BotGroupConfigImpl,
botGroupImpl *impl.BotGroupImpl,
botConfigImpl *impl.BotConfigImpl,
) *DingBotService {
return &DingBotService{
config: config,
dingTalkBotBiz: dingTalkBotBiz,
dingTalkOld: dingTalkOld,
dingtalkCardClient: dingtalkCardClient,
dingtalkImClient: dingtalkImClient,
botGroupConfigImpl: botGroupConfigImpl,
botGroupImpl: botGroupImpl,
botConfigImpl: botConfigImpl,
}
}
@ -170,51 +180,95 @@ func (d *DingBotService) OnCardMessageReceived(ctx context.Context, data *card.C
return nil, nil
}
// 卡片同步回调超时时间为2s2s内同步返回2s后异步更新卡片
startTime := time.Now()
// action 处理 - 这里先只处理第一个匹配的actionId
for _, actionId := range data.CardActionData.CardPrivateData.ActionIdList {
switch actionId {
case constants.CardActionTypeCreateGroup:
// 解析 OutTrackId 以获取 SpaceId 和 BotId
spaceId, botId := constants.ParseCardOutTrackId(data.OutTrackId)
// 群id+机器人id确认一个群配置
var botGroup *model.AiBotGroup
botGroup, err = d.botGroupImpl.GetByConversationIdAndRobotCode(spaceId, botId)
// 获取新群聊人员
var userIds []string
userIds, err = d.buildNewGroupUserIds(ctx, spaceId, botId, data.UserId)
if err != nil {
return nil, err
}
// 获取群配置
var groupConfig model.AiBotGroupConfig
cond := builder.NewCond().And(builder.Eq{"config_id": botGroup.ConfigID})
err = d.botGroupConfigImpl.GetOneBySearchToStrut(&cond, &groupConfig)
if err != nil {
return nil, err
}
// 获取处理人列表
issueOwnerJson := groupConfig.IssueOwner
type issueOwnerType struct {
UserId string `json:"userid"`
Name string `json:"name"`
}
var issueOwner []issueOwnerType
if err = json.Unmarshal([]byte(issueOwnerJson), &issueOwner); err != nil {
return nil, err
}
// 合并所有userid
userIds := []string{data.UserId} // 当前用户为群主
for _, owner := range issueOwner {
userIds = append(userIds, owner.UserId)
}
// 新群分享链接
newGroupShareLink := ""
timeOutLimit := 1500 * time.Millisecond
// 钉钉appKey
appKey := dingtalk.AppKey{}
if data.CardActionData.CardPrivateData.Params["status"] == "confirm" {
// 创建群聊 - 这里用的是“统一登录平台”这个应用的接口
// 不是很关心成功失败ws中后续考虑协程去创建
if _, err = d.dingTalkOld.CreateInternalGroupConversation(ctx, "问题处理群", userIds); err != nil {
chatId, openConversationId, err := d.dingTalkOld.CreateInternalGroupConversation(ctx, "问题处理群", userIds)
if err != nil {
fmt.Printf("创建群聊失败: %v", err)
}
_ = openConversationId
// 获取机器人配置
var botConfig model.AiBotConfig
cond := builder.NewCond().And(builder.Eq{"robot_code": botId})
err = d.botConfigImpl.GetOneBySearchToStrut(&cond, &botConfig)
if err != nil {
return nil, err
}
// 解出 config
var config entitys.DingTalkBot
err = json.Unmarshal([]byte(botConfig.BotConfig), &config)
if err != nil {
log.Printf("配置解析失败 %v", err.Error())
}
appKey = dingtalk.AppKey{
AppKey: config.ClientId,
AppSecret: config.ClientSecret,
}
// 添加当前机器人到新群
_, err = d.dingtalkImClient.AddRobotToConversation(
appKey,
&im_1_0.AddRobotToConversationRequest{
OpenConversationId: tea.String(openConversationId),
RobotCode: tea.String(botId),
})
if err != nil {
fmt.Printf("添加机器人到会话失败: %v", err)
}
// 返回新群分享链接,直接进群
newGroupShareLink, err = d.dingTalkOld.GetJoinGroupQrcode(ctx, chatId, data.UserId)
if err != nil {
fmt.Printf("获取入群二维码失败: %v", err)
}
}
endTime := time.Now()
if endTime.Sub(startTime) > timeOutLimit {
// 异步更新卡片
d.dingtalkCardClient.UpdateCard(appKey, &card_1_0.UpdateCardRequest{
OutTrackId: tea.String(data.OutTrackId),
CardData: &card_1_0.UpdateCardRequestCardData{
CardParamMap: map[string]*string{
"button_display": tea.String("false"),
"new_group_share_link": tea.String(newGroupShareLink),
},
},
CardUpdateOptions: &card_1_0.UpdateCardRequestCardUpdateOptions{
UpdateCardDataByKey: tea.Bool(true),
},
})
return
}
// 构建关闭创建群组卡片按钮的响应
resp = d.buildCreateGroupCardResp()
resp = d.buildCreateGroupCardResp(newGroupShareLink)
return
}
}
@ -222,12 +276,49 @@ func (d *DingBotService) OnCardMessageReceived(ctx context.Context, data *card.C
return &card.CardResponse{}, nil
}
// 关闭创建群组卡片按钮
func (d *DingBotService) buildCreateGroupCardResp() *card.CardResponse {
// buildNewGroupUserIds 构建新群聊人员列表
func (d *DingBotService) buildNewGroupUserIds(ctx context.Context, spaceId, botId, groupOwner string) ([]string, error) {
// 群id+机器人id确认一个群配置
botGroup, err := d.botGroupImpl.GetByConversationIdAndRobotCode(spaceId, botId)
if err != nil {
return nil, err
}
// 获取群配置
var groupConfig model.AiBotGroupConfig
cond := builder.NewCond().And(builder.Eq{"config_id": botGroup.ConfigID})
err = d.botGroupConfigImpl.GetOneBySearchToStrut(&cond, &groupConfig)
if err != nil {
return nil, err
}
// 获取处理人列表
issueOwnerJson := groupConfig.IssueOwner
type issueOwnerType struct {
UserId string `json:"userid"`
Name string `json:"name"`
}
var issueOwner []issueOwnerType
if err = json.Unmarshal([]byte(issueOwnerJson), &issueOwner); err != nil {
return nil, err
}
// 合并所有userid
userIds := []string{groupOwner} // 当前用户为群主
for _, owner := range issueOwner {
userIds = append(userIds, owner.UserId)
}
return userIds, nil
}
// buildCreateGroupCardResp 构建关闭创建群组卡片按钮
func (d *DingBotService) buildCreateGroupCardResp(newGroupShareLink string) *card.CardResponse {
return &card.CardResponse{
CardData: &card.CardDataDto{
CardParamMap: map[string]string{
"button_display": "false",
"button_display": "false",
"new_group_share_link": newGroupShareLink,
},
},
CardUpdateOptions: &card.CardUpdateOptions{