// Package sys // @Link https://github.com/bufanyun/hotgo // @Copyright Copyright (c) 2026 HotGo // @Author Ms <133814250@qq.com> // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE package sys import ( "context" "hotgo/internal/library/imtenant" "hotgo/internal/model/input/sysin" "hotgo/internal/service" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" ) type sSysImGroup struct{} func NewSysImGroup() *sSysImGroup { return &sSysImGroup{} } func init() { service.RegisterSysImGroup(NewSysImGroup()) } // List 获取IM群组列表 func (s *sSysImGroup) List(ctx context.Context, in *sysin.ImGroupListInp) (list []*sysin.ImGroupListModel, totalCount int, err error) { if err = in.Filter(ctx); err != nil { return } db, tenant, err := imtenant.DB(ctx, in.TenantId) if err != nil { return } mod := s.groupModel(ctx, db) mod = s.applyGroupWhere(mod, in) mod = mod.Page(in.Page, in.PerPage).OrderDesc("t.touchedat").OrderDesc("t.id") if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取IM群组列表失败,请稍后重试!") return } for _, item := range list { item.TenantId = tenant.Id item.TenantName = tenant.Name } return } func (s *sSysImGroup) groupModel(ctx context.Context, db gdb.DB) *gdb.Model { return db.Model("im_topics t").Safe().Ctx(ctx). LeftJoin("im_group_settings gs", "gs.topic = t.name"). Fields( "t.name topic", "t.state", "COALESCE(gs.owner_user_id, t.owner) owner_id", "t.seqid seq_id", "t.delid del_id", "t.subcnt sub_cnt", "t.touchedat touched_at", "t.createdat created_at", "t.updatedat updated_at", "t.public public_json", "t.trusted trusted_json", "t.tags tags_json", "t.aux aux_json", "COALESCE(gs.name, '') group_name", "COALESCE(gs.avatar_file_id, '') avatar_file_id", "COALESCE(gs.description, '') description", "COALESCE(gs.group_status, '') group_status", "COALESCE(gs.join_approval, 0) join_approval", "COALESCE(gs.mute_all, 0) mute_all", "COALESCE(gs.member_upload_files, 0) member_upload_files", "COALESCE(gs.member_private_chat, 0) member_private_chat", "COALESCE(gs.member_invite, 0) member_invite", "COALESCE(gs.max_member_count, 0) max_member_count", "COALESCE(gs.max_admin_count, 0) max_admin_count", "COALESCE(gs.member_count, 0) business_member_count", "COALESCE(gs.version, 0) settings_version", "gs.updated_at settings_updated_at", ). WhereLike("t.name", "grp%") } func (s *sSysImGroup) applyGroupWhere(mod *gdb.Model, in *sysin.ImGroupListInp) *gdb.Model { if in.Topic != "" { mod = mod.WhereLike("t.name", "%"+in.Topic+"%") } if in.OwnerId > 0 { mod = mod.Where("COALESCE(gs.owner_user_id, t.owner)", in.OwnerId) } if in.State != nil { mod = mod.Where("t.state", *in.State) } if in.GroupStatus != "" { mod = mod.Where("gs.group_status", in.GroupStatus) } if len(in.CreatedAt) == 2 { mod = mod.WhereBetween("t.createdat", in.CreatedAt[0], in.CreatedAt[1]) } if len(in.TouchedAt) == 2 { mod = mod.WhereBetween("t.touchedat", in.TouchedAt[0], in.TouchedAt[1]) } return mod } // View 获取IM群组指定信息 func (s *sSysImGroup) View(ctx context.Context, in *sysin.ImGroupViewInp) (res *sysin.ImGroupViewModel, err error) { if err = in.Filter(ctx); err != nil { return } db, tenant, err := imtenant.DB(ctx, in.TenantId) if err != nil { return } err = db.Model("im_topics t").Safe().Ctx(ctx). LeftJoin("im_group_settings gs", "gs.topic = t.name"). Fields( "t.name topic", "t.state", "COALESCE(gs.owner_user_id, t.owner) owner_id", "t.seqid seq_id", "t.delid del_id", "t.subcnt sub_cnt", "t.touchedat touched_at", "t.createdat created_at", "t.updatedat updated_at", "t.public public_json", "t.trusted trusted_json", "t.tags tags_json", "t.aux aux_json", "t.access access_json", "t.usebt use_bt", "COALESCE(gs.name, '') group_name", "COALESCE(gs.avatar_file_id, '') avatar_file_id", "COALESCE(gs.description, '') description", "COALESCE(gs.group_status, '') group_status", "COALESCE(gs.join_approval, 0) join_approval", "COALESCE(gs.mute_all, 0) mute_all", "COALESCE(gs.member_upload_files, 0) member_upload_files", "COALESCE(gs.member_private_chat, 0) member_private_chat", "COALESCE(gs.member_invite, 0) member_invite", "COALESCE(gs.max_member_count, 0) max_member_count", "COALESCE(gs.max_admin_count, 0) max_admin_count", "COALESCE(gs.member_count, 0) business_member_count", "COALESCE(gs.version, 0) settings_version", "gs.updated_at settings_updated_at", ). Where("t.name", in.Topic). WhereLike("t.name", "grp%"). Scan(&res) if err != nil { return nil, gerror.Wrap(err, "获取IM群组信息失败,请稍后重试!") } if res == nil { return nil, nil } res.TenantId = tenant.Id res.TenantName = tenant.Name return } // MemberList 获取IM群成员列表 func (s *sSysImGroup) MemberList(ctx context.Context, in *sysin.ImGroupMemberListInp) (list []*sysin.ImGroupMemberListModel, totalCount int, err error) { if err = in.Filter(ctx); err != nil { return } db, _, err := imtenant.DB(ctx, in.TenantId) if err != nil { return } if s.hasGroupMemberTruth(ctx, db, in.Topic) { return s.memberListFromBusiness(ctx, db, in) } return s.memberListFromProjection(ctx, db, in) } func (s *sSysImGroup) hasGroupMemberTruth(ctx context.Context, db gdb.DB, topic string) bool { count, err := db.Model("im_group_members").Safe().Ctx(ctx).Where("topic", topic).Count() return err == nil && count > 0 } func (s *sSysImGroup) memberListFromBusiness(ctx context.Context, db gdb.DB, in *sysin.ImGroupMemberListInp) (list []*sysin.ImGroupMemberListModel, totalCount int, err error) { mod := db.Model("im_group_members gm").Safe().Ctx(ctx). LeftJoin("im_users u", "u.id = gm.user_id"). LeftJoin("im_user_profiles up", "up.user_id = gm.user_id"). LeftJoin("im_subscriptions s", "s.topic = gm.topic AND s.userid = gm.user_id"). Fields( "gm.user_id", "up.nickname", "u.state", "s.modewant mode_want", "s.modegiven mode_given", "s.recvseqid recv_seq_id", "s.readseqid read_seq_id", "s.delid del_id", "s.deletedat deleted_at", "s.createdat created_at", "s.updatedat updated_at", "s.private private_json", "gm.role", "gm.member_status", "gm.nickname group_nickname", "gm.pinned", "gm.mute_notifications", "gm.join_source", "gm.joined_by", "gm.joined_at", "gm.left_at", "gm.removed_by", "gm.version", ). Where("gm.topic", in.Topic) if in.UserId > 0 { mod = mod.Where("gm.user_id", in.UserId) } if in.Role != "" { mod = mod.Where("gm.role", in.Role) } if in.MemberStatus != "" { mod = mod.Where("gm.member_status", in.MemberStatus) } mod = mod.Page(in.Page, in.PerPage).OrderAsc("gm.member_status").OrderAsc("gm.role").OrderAsc("gm.id") if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取IM群成员列表失败,请稍后重试!") return } return } func (s *sSysImGroup) memberListFromProjection(ctx context.Context, db gdb.DB, in *sysin.ImGroupMemberListInp) (list []*sysin.ImGroupMemberListModel, totalCount int, err error) { mod := db.Model("im_subscriptions s").Safe().Ctx(ctx). LeftJoin("im_users u", "u.id = s.userid"). LeftJoin("im_user_profiles up", "up.user_id = s.userid"). Fields( "s.userid user_id", "up.nickname", "u.state", "s.modewant mode_want", "s.modegiven mode_given", "s.recvseqid recv_seq_id", "s.readseqid read_seq_id", "s.delid del_id", "s.deletedat deleted_at", "s.createdat created_at", "s.updatedat updated_at", "s.private private_json", "'member' role", "IF(s.deletedat IS NULL, 'active', 'left') member_status", "'' group_nickname", "0 pinned", "0 mute_notifications", "'projection' join_source", "0 joined_by", "s.createdat joined_at", "s.deletedat left_at", "0 removed_by", "0 version", ). Where("s.topic", in.Topic) if in.UserId > 0 { mod = mod.Where("s.userid", in.UserId) } mod = mod.Page(in.Page, in.PerPage).OrderAsc("s.deletedat").OrderAsc("s.userid") if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取IM群成员列表失败,请稍后重试!") return } return } // Governance 获取IM群治理配置 func (s *sSysImGroup) Governance(ctx context.Context, in *sysin.ImGroupTopicInp) (res *sysin.ImGroupGovernanceModel, err error) { if err = in.Filter(ctx); err != nil { return } db, tenant, err := imtenant.DB(ctx, in.TenantId) if err != nil { return nil, err } err = db.Model("im_group_settings").Safe().Ctx(ctx). Fields( "topic", "owner_user_id", "name", "avatar_file_id", "description", "group_status", "join_approval", "mute_all", "member_upload_files", "member_private_chat", "member_invite", "max_member_count", "max_admin_count", "member_count", "version", "created_by", "dissolved_by", "dissolved_at", "created_at", "updated_at", ). Where("topic", in.Topic). Scan(&res) if err != nil { return nil, gerror.Wrap(err, "获取IM群治理配置失败,请稍后重试!") } if res == nil { return nil, nil } res.TenantId = tenant.Id res.TenantName = tenant.Name return } // JoinRequestList 获取IM入群申请列表 func (s *sSysImGroup) JoinRequestList(ctx context.Context, in *sysin.ImGroupJoinRequestListInp) (list []*sysin.ImGroupJoinRequestListModel, totalCount int, err error) { if err = in.Filter(ctx); err != nil { return } db, _, err := imtenant.DB(ctx, in.TenantId) if err != nil { return } mod := db.Model("im_group_join_requests").Safe().Ctx(ctx).Where("topic", in.Topic) if in.Status != "" { mod = mod.Where("status", in.Status) } if in.ApplicantUserId > 0 { mod = mod.Where("applicant_user_id", in.ApplicantUserId) } mod = mod.Page(in.Page, in.PerPage).OrderDesc("id") if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取IM入群申请列表失败,请稍后重试!") } return } // InvitationList 获取IM群邀请列表 func (s *sSysImGroup) InvitationList(ctx context.Context, in *sysin.ImGroupInvitationListInp) (list []*sysin.ImGroupInvitationListModel, totalCount int, err error) { if err = in.Filter(ctx); err != nil { return } db, _, err := imtenant.DB(ctx, in.TenantId) if err != nil { return } mod := db.Model("im_group_invitations").Safe().Ctx(ctx).Where("topic", in.Topic) if in.Status != "" { mod = mod.Where("status", in.Status) } if in.TargetUserId > 0 { mod = mod.Where("target_user_id", in.TargetUserId) } if in.InviterUserId > 0 { mod = mod.Where("inviter_user_id", in.InviterUserId) } mod = mod.Page(in.Page, in.PerPage).OrderDesc("id") if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取IM群邀请列表失败,请稍后重试!") } return } // AnnouncementList 获取IM群公告列表 func (s *sSysImGroup) AnnouncementList(ctx context.Context, in *sysin.ImGroupAnnouncementListInp) (list []*sysin.ImGroupAnnouncementListModel, totalCount int, err error) { if err = in.Filter(ctx); err != nil { return } db, _, err := imtenant.DB(ctx, in.TenantId) if err != nil { return } mod := db.Model("im_group_announcements").Safe().Ctx(ctx).Where("topic", in.Topic) if in.Status != "" { mod = mod.Where("status", in.Status) } mod = mod.Page(in.Page, in.PerPage).OrderDesc("published_at").OrderDesc("id") if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取IM群公告列表失败,请稍后重试!") } return } // MuteList 获取IM群禁言列表 func (s *sSysImGroup) MuteList(ctx context.Context, in *sysin.ImGroupMuteListInp) (list []*sysin.ImGroupMuteListModel, totalCount int, err error) { if err = in.Filter(ctx); err != nil { return } db, _, err := imtenant.DB(ctx, in.TenantId) if err != nil { return } mod := db.Model("im_group_mutes").Safe().Ctx(ctx).Where("topic", in.Topic) if in.Status != "" { mod = mod.Where("status", in.Status) } if in.UserId > 0 { mod = mod.Where("user_id", in.UserId) } mod = mod.Page(in.Page, in.PerPage).OrderDesc("muted_at").OrderDesc("user_id") if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取IM群禁言列表失败,请稍后重试!") } return } // AdminLogList 获取IM群管理日志列表 func (s *sSysImGroup) AdminLogList(ctx context.Context, in *sysin.ImGroupAdminLogListInp) (list []*sysin.ImGroupAdminLogListModel, totalCount int, err error) { if err = in.Filter(ctx); err != nil { return } db, _, err := imtenant.DB(ctx, in.TenantId) if err != nil { return } mod := db.Model("im_group_admin_logs").Safe().Ctx(ctx). Fields( "id", "log_id", "topic", "operator_id", "target_user_id", "action", "object_type", "object_id", "CAST(before_data AS CHAR) before_data", "CAST(after_data AS CHAR) after_data", "request_id", "idempotency_key", "created_at", ). Where("topic", in.Topic) if in.Action != "" { mod = mod.WhereLike("action", "%"+in.Action+"%") } if in.OperatorId > 0 { mod = mod.Where("operator_id", in.OperatorId) } mod = mod.Page(in.Page, in.PerPage).OrderDesc("id") if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取IM群管理日志列表失败,请稍后重试!") } return }