From a131bf5cce580f9ecb01bdcb64b3f38c2816484b Mon Sep 17 00:00:00 2001 From: Yangtao Date: Fri, 28 Nov 2025 13:24:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=BA=91=E4=BF=A1?= =?UTF-8?q?=E7=BE=A4=E7=BB=84api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/common/app_const.go | 4 +- pkg/common/netease/ImClient.go | 284 ++++++++++++++++++++++++++++++++- 2 files changed, 286 insertions(+), 2 deletions(-) diff --git a/pkg/common/app_const.go b/pkg/common/app_const.go index f1415b8..0575855 100644 --- a/pkg/common/app_const.go +++ b/pkg/common/app_const.go @@ -38,7 +38,9 @@ const ( DateDefaultFormat = "Y-m-d" //post请求 - HTTP_METHOD_POST = "POST" + HTTP_METHOD_POST = "POST" + HTTP_METHOD_PATCH = "PATCH" + HTTP_METHOD_DELETE = "DELETE" // 消费单位名称 CONSUME_UNIT_NAME = "钻石" diff --git a/pkg/common/netease/ImClient.go b/pkg/common/netease/ImClient.go index 354a994..1a1f89b 100644 --- a/pkg/common/netease/ImClient.go +++ b/pkg/common/netease/ImClient.go @@ -689,7 +689,6 @@ func (client *ImClient) SendAttachMsg(parameters map[string]string) error { // CreateChatGroup 创建群组 func (client *ImClient) CreateChatGroup(ctx context.Context, ownerUserId string, groupName string, inviteMem []string) (string, error) { - url := "https://open.yunxinapi.com/im/v2.1/teams" httpMethod := common.HTTP_METHOD_POST header := client.generateJsonHeader() @@ -736,6 +735,289 @@ func (client *ImClient) CreateChatGroup(ctx context.Context, ownerUserId string, return cast.ToString(body.Data.TeamInfo.TeamID), nil } +// 创建云信账户 +// 创建高级群,创建时即可通过设置群成员列表邀请用户入群。 +// 建群成功会返回 tid,网易云信服务器产生,群唯一标识,该字段需要保存,以便于加人与踢人等后续操作。 +// 如果创建时邀请的成员中存在加群数量超过限制的情况,会返回 faccid(加群失败成员的 IM 账号)。 +// 每个用户可创建的群数量有限制,限制值由 IM 套餐的群组配置决定,具体可前往 网易云信控制台 查看。 +func (client *ImClient) CreateProGroup(tname, owner, announcement, avatar string) (string, error) { + url := "https://api.netease.im/nimserver/team/create.action" + httpMethod := common.HTTP_METHOD_POST + header := client.generateHeader() + sb := HyTools.NewStringBuilder() + sb.Append("tname=" + tname) + sb.Append("&") + sb.Append("owner=owner") + sb.Append("&") + sb.Append("announcement=" + announcement) + sb.Append("&") + sb.Append("icon=" + avatar) + sb.Append("&") + sb.Append("joinmode=" + "0") + sb.Append("&") + sb.Append("invitemode=" + "1") // 邀请权限,即谁可以邀请他人入群0,群主和管理员(默认)。1,所有人 + sb.Append("&") + sb.Append("teamMemberLimit=" + "3000") // 最大群成员数(包含群主),[2,200(默认)] + sb.Append("&") + sb.Append("isNotifyCloseOnline=" + "0") // 是否关闭群通知消息在线发送0,否。1,是 + sb.Append("&") + sb.Append("isNotifyClosePersistent=" + "0") // 是否关闭存储离线/漫游/历史的群通知消息0,否。1,是 + res, err := HyTools.HttpDo(httpMethod, url, header, sb.ToString()) + // code Integer 状态码 + // tid Long 网易云信服务器产生,群唯一标识 + // faccid String 入群失败的账号(accid)列表,格式为 JSONArray,如果创建时邀请的成员中存在加群数量超过限制的情况,会返回入群失败的 accid 以及附言(msg) + if err != nil { + // {"desc":"already register","code":414} + log.Info("CreateProGroup %s:" + err.Error()) + return "", err + } else { + var resDTO CreateImRes + json.Unmarshal([]byte(res), &resDTO) + if resDTO.Code != 200 { + log.Info("CreateProGroup_%s:" + resDTO.Desc) + } else { + log.Info("CreateProGroup_%s:" + res) + } + } + var body map[string]any + if errJson := json.Unmarshal([]byte(res), &body); errJson != nil { + return "", errJson + } + if int(body["code"].(float64)) != 200 { + return "", errors.New(body["desc"].(string)) + } + return body["tid"].(string), nil +} + +// GroupUpdate 更新群组 +func (client *ImClient) GroupUpdate(ctx context.Context, id, operator_id, name, announcement, icon string) error { + url := "https://open.yunxinapi.com/im/v2.1/teams/" + id + httpMethod := common.HTTP_METHOD_PATCH + header := client.generateJsonHeader() + reqBody := map[string]any{ + "operator_id": operator_id, + "team_type": 1, + "name": name, + "announcement": announcement, + // "intro": intro, + // "members_limit": members_limit, + // "join_mode": join_mode, 通过 SDK 侧操作申请入群的验证方式。 0(默认):无需验证,直接入群。 1:需要群主或管理员验证通过才能入群。 2:不允许任何人申请入群。 + // "agree_mode": agree_mode, 邀请入群时是否需要被邀请人的同意。0(默认):需要被邀请人同意才能入群。1:不需要被邀请人同意,直接入群。 + // "invite_mode": invite_mode, 邀请权限,即谁可以邀请他人入群。0(默认):群主和管理员。1:所有人。 + } + bodyBytes, err := json.Marshal(reqBody) + if err != nil { + return errors.WithStack(err) + } + res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes)) + if err != nil { + log.InfoF("GroupUpdate %s:"+err.Error(), operator_id) + return errors.WithStack(err) + } + log.InfoF("update group chat resp: %s", res) + var body BaseRes[CreateChatGroupRsp] + err = json.Unmarshal([]byte(res), &body) + if err != nil { + return errors.WithStack(err) + } + if body.Code != 200 { + return errors.Errorf("GroupUpdate code(%d) not 200,msg: %s", body.Code, body.Msg) + } + return nil +} + +// GroupTransfer 转让群组 +func (client *ImClient) GroupTransfer(ctx context.Context, id, new_owner, extension string) error { + url := "https://open.yunxinapi.com/im/v2.1/teams/" + id + "/actions/transfer_owner" + httpMethod := common.HTTP_METHOD_PATCH + header := client.generateJsonHeader() + reqBody := map[string]any{ + "team_type": 1, + "new_owner_account_id": new_owner, + "leave": 2, + "extension": extension, + } + bodyBytes, err := json.Marshal(reqBody) + if err != nil { + return errors.WithStack(err) + } + res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes)) + if err != nil { + log.InfoF("GroupTransfer %s:"+err.Error(), id) + return errors.WithStack(err) + } + log.InfoF("GroupTransfer group chat resp: %s", res) + var body BaseRes[CreateChatGroupRsp] + err = json.Unmarshal([]byte(res), &body) + if err != nil { + return errors.WithStack(err) + } + if body.Code != 200 { + return errors.Errorf("GroupTransfer code(%d) not 200,msg: %s", body.Code, body.Msg) + } + return nil +} + +// GroupManagerAdd +func (client *ImClient) GroupManagerAdd(ctx context.Context, id, operator_id, extension string, managers []string) error { + url := "https://open.yunxinapi.com/im/v2.1/teams/" + id + "/actions/add_manager" + httpMethod := common.HTTP_METHOD_POST + header := client.generateJsonHeader() + reqBody := map[string]any{ + "team_type": 1, + "managers": managers, + "operator_id": operator_id, + "extension": extension, + } + bodyBytes, err := json.Marshal(reqBody) + if err != nil { + return errors.WithStack(err) + } + res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes)) + if err != nil { + log.InfoF("GroupManagerAdd %s:"+err.Error(), operator_id) + return errors.WithStack(err) + } + log.InfoF("GroupManagerAdd group chat resp: %s", res) + var body BaseRes[CreateChatGroupRsp] + err = json.Unmarshal([]byte(res), &body) + if err != nil { + return errors.WithStack(err) + } + if body.Code != 200 { + return errors.Errorf("GroupManagerAdd code(%d) not 200,msg: %s", body.Code, body.Msg) + } + return nil +} + +// GroupManagerRemove +func (client *ImClient) GroupManagerRemove(ctx context.Context, id, operator_id, extension string, managers []string) error { + url := "https://open.yunxinapi.com/im/v2.1/teams/" + id + "/actions/remove_manager" + httpMethod := common.HTTP_METHOD_DELETE + header := client.generateJsonHeader() + reqBody := map[string]any{ + "team_type": 1, + "managers": managers, + "operator_id": operator_id, + "extension": extension, + } + bodyBytes, err := json.Marshal(reqBody) + if err != nil { + return errors.WithStack(err) + } + res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes)) + if err != nil { + log.InfoF("GroupManagerRemove %s:"+err.Error(), operator_id) + return errors.WithStack(err) + } + log.InfoF("GroupManagerRemove group chat resp: %s", res) + var body BaseRes[CreateChatGroupRsp] + err = json.Unmarshal([]byte(res), &body) + if err != nil { + return errors.WithStack(err) + } + if body.Code != 200 { + return errors.Errorf("GroupManagerRemove code(%d) not 200,msg: %s", body.Code, body.Msg) + } + return nil +} + +// GroupRemove +func (client *ImClient) GroupRemove(ctx context.Context, id, operator_id, extension string) error { + url := "https://open.yunxinapi.com/im/v2.1/teams/" + id + httpMethod := common.HTTP_METHOD_DELETE + header := client.generateJsonHeader() + reqBody := map[string]any{ + "team_type": 1, + "operator_id": operator_id, + "extension": extension, + } + bodyBytes, err := json.Marshal(reqBody) + if err != nil { + return errors.WithStack(err) + } + res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes)) + if err != nil { + log.InfoF("GroupRemove %s:"+err.Error(), operator_id) + return errors.WithStack(err) + } + log.InfoF("GroupRemove group chat resp: %s", res) + var body BaseRes[CreateChatGroupRsp] + err = json.Unmarshal([]byte(res), &body) + if err != nil { + return errors.WithStack(err) + } + if body.Code != 200 { + return errors.Errorf("GroupRemove code(%d) not 200,msg: %s", body.Code, body.Msg) + } + return nil +} + +// GroupMemberKick +func (client *ImClient) GroupMemberKick(ctx context.Context, tid, operator_id, extension string, members []string) error { + url := "https://open.yunxinapi.com/im/v2/team_members/actions/kick_member" + httpMethod := common.HTTP_METHOD_DELETE + header := client.generateJsonHeader() + reqBody := map[string]any{ + "team_type": 1, + "operator_id": operator_id, + "team_id": tid, + "kick_account_ids": members, + "extension": extension, + } + bodyBytes, err := json.Marshal(reqBody) + if err != nil { + return errors.WithStack(err) + } + res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes)) + if err != nil { + log.InfoF("GroupMemberKick %s:"+err.Error(), operator_id) + return errors.WithStack(err) + } + log.InfoF("GroupMemberKick group chat resp: %s", res) + var body BaseRes[CreateChatGroupRsp] + err = json.Unmarshal([]byte(res), &body) + if err != nil { + return errors.WithStack(err) + } + if body.Code != 200 { + return errors.Errorf("GroupMemberKick code(%d) not 200,msg: %s", body.Code, body.Msg) + } + return nil +} + +// GroupMemberLeave +func (client *ImClient) GroupMemberLeave(ctx context.Context, tid, account_id, extension string, members []string) error { + url := "https://open.yunxinapi.com/im/v2/team_members/actions/leave" + httpMethod := common.HTTP_METHOD_DELETE + header := client.generateJsonHeader() + reqBody := map[string]any{ + "team_type": 1, + "account_id": account_id, + "team_id": tid, + "extension": extension, + } + bodyBytes, err := json.Marshal(reqBody) + if err != nil { + return errors.WithStack(err) + } + res, err := HyTools.HttpDo(httpMethod, url, header, string(bodyBytes)) + if err != nil { + log.InfoF("GroupMemberLeave %s:"+err.Error(), tid) + return errors.WithStack(err) + } + log.InfoF("GroupMemberLeave group chat resp: %s", res) + var body BaseRes[CreateChatGroupRsp] + err = json.Unmarshal([]byte(res), &body) + if err != nil { + return errors.WithStack(err) + } + if body.Code != 200 { + return errors.Errorf("GroupMemberLeave code(%d) not 200,msg: %s", body.Code, body.Msg) + } + return nil +} + // ================ 私有方法 ======================== func generateBodyData(parameters map[string]string) string { sb := htools.NewStringBuilder()