fix: 1.增加回调 OutTrackId 模板处理 2.群组查询增加状态判断 3.群组配置表增加群组问题处理人字段 4.增加卡片更新方法,调整回调执行逻辑

This commit is contained in:
fuzhongyun 2026-01-21 14:42:14 +08:00
parent 17d7b01fdf
commit a0b76f1581
6 changed files with 152 additions and 26 deletions

View File

@ -32,7 +32,6 @@ import (
"github.com/alibabacloud-go/tea/tea"
"github.com/coze-dev/coze-go"
"github.com/gofiber/fiber/v2/log"
"github.com/google/uuid"
"xorm.io/builder"
)
@ -506,14 +505,16 @@ func (g *GroupConfigBiz) handleKnowledgeV2(ctx context.Context, rec *entitys.Rec
// 未检索到匹配信息,询问是否拉群
if !isRetrieved {
// 构建卡片 OutTrackId
outTrackId := constants.BuildCardOutTrackId("cidwP24PLZhLVOS2dVIkEawLw==", "ding5wwvnf9hxeyjau7t")
// 发送钉钉卡片
uuid := uuid.New().String()
_, err = g.dingtalkCardClient.CreateAndDeliver(dingtalk.AppKey{
AppKey: "ding5wwvnf9hxeyjau7t",
AppSecret: "FxXVlTzxrKXvJ8h-9uK0s5TjaBfOJSXumpmrHal-NmQAtku9wOPxcss0Af6WHoAK",
}, &card_1_0.CreateAndDeliverRequest{
CardTemplateId: tea.String("faad6d5d-726d-467f-a6ba-28c1930aa5f3.schema"),
OutTrackId: tea.String(uuid),
OutTrackId: tea.String(outTrackId),
CallbackType: tea.String("STREAM"),
CardData: &card_1_0.CreateAndDeliverRequestCardData{
CardParamMap: map[string]*string{
@ -525,6 +526,7 @@ func (g *GroupConfigBiz) handleKnowledgeV2(ctx context.Context, rec *entitys.Rec
"button_right": tea.String("忽略"),
"button_right_link": tea.String(""),
"action_id": tea.String("create_group"),
"button_display": tea.String("true"),
"_CARD_DEBUG_TOOL_ENTRY": tea.String("show"),
},
},
@ -534,9 +536,9 @@ func (g *GroupConfigBiz) handleKnowledgeV2(ctx context.Context, rec *entitys.Rec
OpenSpaceId: tea.String("dtv1.card//im_group.cidwP24PLZhLVOS2dVIkEawLw=="),
ImGroupOpenDeliverModel: &card_1_0.CreateAndDeliverRequestImGroupOpenDeliverModel{
RobotCode: tea.String("ding5wwvnf9hxeyjau7t"),
// Recipients: []*string{
// tea.String("17415698414368678"),
// },
Recipients: []*string{
tea.String("17415698414368678"),
},
},
})
if err != nil {

View File

@ -1,6 +1,11 @@
package constants
import "net/url"
import (
"net/url"
"strings"
"github.com/google/uuid"
)
const DingTalkBseUrl = "https://oapi.dingtalk.com"
@ -79,7 +84,35 @@ const (
}`
)
// 交互卡片回调类型
const (
CardActionCallbackTypeAction string = "actionCallback" // 交互卡片回调事件类型
)
// 交互卡片回调事件类型
const (
CardActionTypeCreateGroup string = "create_group" // 创建群聊
)
// dingtalk 卡片 OutTrackId 模板
const CardOutTrackIdTemplate string = "{space_id}:{bot_id}:{uuid}"
func BuildCardOutTrackId(spaceId string, botId string) (outTrackId string) {
uuid := uuid.New().String()
outTrackId = strings.ReplaceAll(CardOutTrackIdTemplate, "{space_id}", spaceId)
outTrackId = strings.ReplaceAll(outTrackId, "{bot_id}", botId)
outTrackId = strings.ReplaceAll(outTrackId, "{uuid}", uuid)
return
}
func ParseCardOutTrackId(outTrackId string) (spaceId string, botId string) {
parts := strings.Split(outTrackId, ":")
if len(parts) != 3 {
return
}
spaceId, botId, _ = parts[0], parts[1], parts[2]
return
}

View File

@ -19,7 +19,7 @@ func NewBotGroupImpl(db *utils.Db) *BotGroupImpl {
func (k BotGroupImpl) GetByConversationIdAndRobotCode(staffId string, robotCode string) (*model.AiBotGroup, error) {
var data model.AiBotGroup
err := k.Db.Model(k.Model).Where("conversation_id = ? and robot_code = ?", staffId, robotCode).Find(&data).Error
err := k.Db.Model(k.Model).Where("conversation_id = ? and robot_code = ? and status = 1", staffId, robotCode).Find(&data).Error
if data.GroupID == 0 {
err = sql.ErrNoRows
}

View File

@ -11,6 +11,7 @@ type AiBotGroupConfig struct {
ConfigID int32 `gorm:"column:config_id;primaryKey;autoIncrement:true" json:"config_id"`
ToolList string `gorm:"column:tool_list;not null" json:"tool_list"`
ProductName string `gorm:"column:product_name;not null" json:"product_name"`
IssueOwner string `gorm:"column:issue_owner;comment:群组问题处理人" json:"issue_owner"` // 群组问题处理人
}
// TableName AiBotGroupConfig's table name

View File

@ -58,3 +58,28 @@ func (c *CardClient) CreateAndDeliver(req AppKey, cardData *card.CreateAndDelive
return true, nil
}
// 更新卡片
func (c *CardClient) UpdateCard(req AppKey, cardData *card.UpdateCardRequest) (bool, error) {
// 获取token
accessToken, err := c.oauth2Client.GetAccessToken(req)
if err != nil {
return false, err
}
// 调用API
resp, err := c.cli.UpdateCardWithOptions(
cardData,
&card.UpdateCardHeaders{XAcsDingtalkAccessToken: tea.String(accessToken)},
&util.RuntimeOptions{},
)
if err != nil {
return false, err
}
if resp.Body == nil {
return false, errorcode.ParamErrf("empty response body")
}
return *resp.Body.Success, nil
}

View File

@ -4,6 +4,8 @@ import (
"ai_scheduler/internal/biz"
"ai_scheduler/internal/config"
"ai_scheduler/internal/data/constants"
"ai_scheduler/internal/data/impl"
"ai_scheduler/internal/data/model"
"ai_scheduler/internal/entitys"
"ai_scheduler/internal/pkg/dingtalk"
"context"
@ -15,19 +17,33 @@ import (
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/card"
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
"golang.org/x/sync/errgroup"
"xorm.io/builder"
)
type DingBotService struct {
config *config.Config
dingTalkBotBiz *biz.DingTalkBotBiz
dingTalkOld *dingtalk.OldClient
config *config.Config
dingTalkBotBiz *biz.DingTalkBotBiz
dingTalkOld *dingtalk.OldClient
dingtalkCardClient *dingtalk.CardClient
botGroupConfigImpl *impl.BotGroupConfigImpl
botGroupImpl *impl.BotGroupImpl
}
func NewDingBotService(config *config.Config, dingTalkBotBiz *biz.DingTalkBotBiz, dingTalkOld *dingtalk.OldClient) *DingBotService {
func NewDingBotService(
config *config.Config,
dingTalkBotBiz *biz.DingTalkBotBiz,
dingTalkOld *dingtalk.OldClient,
dingtalkCardClient *dingtalk.CardClient,
botGroupConfigImpl *impl.BotGroupConfigImpl,
botGroupImpl *impl.BotGroupImpl,
) *DingBotService {
return &DingBotService{
config: config,
dingTalkBotBiz: dingTalkBotBiz,
dingTalkOld: dingTalkOld,
config: config,
dingTalkBotBiz: dingTalkBotBiz,
dingTalkOld: dingTalkOld,
dingtalkCardClient: dingtalkCardClient,
botGroupConfigImpl: botGroupConfigImpl,
botGroupImpl: botGroupImpl,
}
}
@ -147,26 +163,75 @@ func (d *DingBotService) runBackgroundTasks(ctx context.Context, data *chatbot.B
return nil
}
// **一把梭先搞,后续规范化**
func (d *DingBotService) OnCardMessageReceived(ctx context.Context, data *card.CardRequest) (resp *card.CardResponse, err error) {
// 解content
var cardActionData card.PrivateCardActionData
if err = json.Unmarshal([]byte(data.Content), &cardActionData); err != nil {
return nil, err
// 非回调类型暂不接受
if data.Type != constants.CardActionCallbackTypeAction {
return nil, nil
}
// action 处理
for _, actionId := range cardActionData.CardPrivateData.ActionIdList {
// action 处理 - 这里先只处理第一个匹配的actionId
for _, actionId := range data.CardActionData.CardPrivateData.ActionIdList {
switch actionId {
case constants.CardActionTypeCreateGroup:
if cardActionData.CardPrivateData.Params["status"] != "confirm" {
continue
}
// 创建群聊
if _, err = d.dingTalkOld.CreateInternalGroupConversation(ctx, "问题处理群", []string{"17415698414368678", "17101201090101570"}); err != nil {
// 解析 OutTrackId 以获取 SpaceId 和 BotId
spaceId, botId := constants.ParseCardOutTrackId(data.OutTrackId)
// 群id+机器人id确认一个群配置
var botGroup *model.AiBotGroup
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{data.UserId} // 当前用户为群主
for _, owner := range issueOwner {
userIds = append(userIds, owner.UserId)
}
if data.CardActionData.CardPrivateData.Params["status"] == "confirm" {
// 创建群聊 - 这里用的是“统一登录平台”这个应用的接口
// 不是很关心成功失败ws中后续考虑协程去创建
if _, err = d.dingTalkOld.CreateInternalGroupConversation(ctx, "问题处理群", userIds); err != nil {
return nil, err
}
}
// 构建关闭创建群组卡片按钮的响应
resp = d.buildCreateGroupCardResp()
return
}
}
return &card.CardResponse{}, nil
}
// 关闭创建群组卡片按钮
func (d *DingBotService) buildCreateGroupCardResp() *card.CardResponse {
return &card.CardResponse{
CardData: &card.CardDataDto{
CardParamMap: map[string]string{
"button_display": "false",
},
},
CardUpdateOptions: &card.CardUpdateOptions{
UpdateCardDataByKey: true,
},
}
}