2026-04-22 16:01:59 +08:00
|
|
|
|
package service
|
2026-03-14 18:01:55 +08:00
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"errors"
|
|
|
|
|
|
|
2026-04-22 16:01:59 +08:00
|
|
|
|
"with_you/internal/dto"
|
|
|
|
|
|
"with_you/internal/model"
|
|
|
|
|
|
"with_you/internal/repository"
|
2026-03-14 18:01:55 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// AdminGroupService 管理端群组服务接口
|
|
|
|
|
|
type AdminGroupService interface {
|
|
|
|
|
|
// GetGroupList 获取群组列表(分页、搜索、筛选)
|
|
|
|
|
|
GetGroupList(ctx context.Context, page, pageSize int, keyword, status, ownerID, startDate, endDate string) ([]dto.AdminGroupListResponse, int64, error)
|
|
|
|
|
|
// GetGroupDetail 获取群组详情
|
|
|
|
|
|
GetGroupDetail(ctx context.Context, groupID string) (*dto.AdminGroupDetailResponse, error)
|
|
|
|
|
|
// GetGroupMembers 获取群组成员列表
|
|
|
|
|
|
GetGroupMembers(ctx context.Context, groupID string, page, pageSize int) (*dto.AdminGroupMemberListResponse, error)
|
|
|
|
|
|
// DeleteGroup 解散群组
|
|
|
|
|
|
DeleteGroup(ctx context.Context, groupID string) error
|
|
|
|
|
|
// UpdateGroupStatus 更新群组状态
|
|
|
|
|
|
UpdateGroupStatus(ctx context.Context, groupID string, status string) (*dto.AdminGroupDetailResponse, error)
|
|
|
|
|
|
// RemoveMember 移除群组成员
|
|
|
|
|
|
RemoveMember(ctx context.Context, groupID string, userID string) error
|
|
|
|
|
|
// TransferOwner 转让群主
|
|
|
|
|
|
TransferOwner(ctx context.Context, groupID string, newOwnerID string) (*dto.AdminGroupDetailResponse, error)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// adminGroupServiceImpl 管理端群组服务实现
|
|
|
|
|
|
type adminGroupServiceImpl struct {
|
|
|
|
|
|
groupRepo repository.GroupRepository
|
2026-03-26 18:14:16 +08:00
|
|
|
|
userRepo repository.UserRepository
|
2026-03-14 18:01:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewAdminGroupService 创建管理端群组服务
|
|
|
|
|
|
func NewAdminGroupService(
|
|
|
|
|
|
groupRepo repository.GroupRepository,
|
2026-03-26 18:14:16 +08:00
|
|
|
|
userRepo repository.UserRepository,
|
2026-03-14 18:01:55 +08:00
|
|
|
|
) AdminGroupService {
|
|
|
|
|
|
return &adminGroupServiceImpl{
|
|
|
|
|
|
groupRepo: groupRepo,
|
|
|
|
|
|
userRepo: userRepo,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetGroupList 获取群组列表
|
|
|
|
|
|
func (s *adminGroupServiceImpl) GetGroupList(ctx context.Context, page, pageSize int, keyword, status, ownerID, startDate, endDate string) ([]dto.AdminGroupListResponse, int64, error) {
|
|
|
|
|
|
groups, total, err := s.groupRepo.GetGroupList(page, pageSize, keyword, status, ownerID, startDate, endDate)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, 0, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
responses := make([]dto.AdminGroupListResponse, 0, len(groups))
|
|
|
|
|
|
for _, group := range groups {
|
|
|
|
|
|
response := dto.AdminGroupListResponse{
|
|
|
|
|
|
ID: group.ID,
|
|
|
|
|
|
Name: group.Name,
|
|
|
|
|
|
Avatar: group.Avatar,
|
|
|
|
|
|
Description: group.Description,
|
|
|
|
|
|
OwnerID: group.OwnerID,
|
|
|
|
|
|
MemberCount: group.MemberCount,
|
|
|
|
|
|
MaxMembers: group.MaxMembers,
|
|
|
|
|
|
JoinType: int(group.JoinType),
|
|
|
|
|
|
MuteAll: group.MuteAll,
|
|
|
|
|
|
Status: "active", // 默认状态为active,后续可以根据需要添加状态字段
|
|
|
|
|
|
CreatedAt: dto.FormatTime(group.CreatedAt),
|
|
|
|
|
|
UpdatedAt: dto.FormatTime(group.UpdatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取群主信息
|
|
|
|
|
|
if group.OwnerID != "" {
|
|
|
|
|
|
owner, err := s.userRepo.GetByID(group.OwnerID)
|
|
|
|
|
|
if err == nil && owner != nil {
|
|
|
|
|
|
response.Owner = &dto.UserResponse{
|
|
|
|
|
|
ID: owner.ID,
|
|
|
|
|
|
Username: owner.Username,
|
|
|
|
|
|
Nickname: owner.Nickname,
|
|
|
|
|
|
Avatar: owner.Avatar,
|
|
|
|
|
|
CreatedAt: dto.FormatTime(owner.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取帖子数量
|
|
|
|
|
|
postCount, _ := s.groupRepo.GetGroupPostCount(group.ID)
|
|
|
|
|
|
response.PostCount = postCount
|
|
|
|
|
|
|
|
|
|
|
|
responses = append(responses, response)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return responses, total, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetGroupDetail 获取群组详情
|
|
|
|
|
|
func (s *adminGroupServiceImpl) GetGroupDetail(ctx context.Context, groupID string) (*dto.AdminGroupDetailResponse, error) {
|
|
|
|
|
|
group, err := s.groupRepo.GetByID(groupID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
response := &dto.AdminGroupDetailResponse{
|
|
|
|
|
|
ID: group.ID,
|
|
|
|
|
|
Name: group.Name,
|
|
|
|
|
|
Avatar: group.Avatar,
|
|
|
|
|
|
Description: group.Description,
|
|
|
|
|
|
OwnerID: group.OwnerID,
|
|
|
|
|
|
MemberCount: group.MemberCount,
|
|
|
|
|
|
MaxMembers: group.MaxMembers,
|
|
|
|
|
|
JoinType: int(group.JoinType),
|
|
|
|
|
|
MuteAll: group.MuteAll,
|
|
|
|
|
|
Status: "active",
|
|
|
|
|
|
IsPublic: true, // 默认为公开群组,后续可以根据需要添加字段
|
|
|
|
|
|
CreatedAt: dto.FormatTime(group.CreatedAt),
|
|
|
|
|
|
UpdatedAt: dto.FormatTime(group.UpdatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取群主信息
|
|
|
|
|
|
if group.OwnerID != "" {
|
|
|
|
|
|
owner, err := s.userRepo.GetByID(group.OwnerID)
|
|
|
|
|
|
if err == nil && owner != nil {
|
2026-03-19 13:49:51 +08:00
|
|
|
|
response.Owner = dto.ConvertUserToResponse(owner)
|
2026-03-14 18:01:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取帖子数量
|
|
|
|
|
|
postCount, _ := s.groupRepo.GetGroupPostCount(group.ID)
|
|
|
|
|
|
response.PostCount = postCount
|
|
|
|
|
|
|
|
|
|
|
|
// 获取最新公告
|
|
|
|
|
|
announcement, _ := s.groupRepo.GetLatestAnnouncement(groupID)
|
|
|
|
|
|
if announcement != nil {
|
|
|
|
|
|
response.Announcement = &dto.GroupAnnouncementResponse{
|
|
|
|
|
|
ID: announcement.ID,
|
|
|
|
|
|
GroupID: announcement.GroupID,
|
|
|
|
|
|
Content: announcement.Content,
|
|
|
|
|
|
AuthorID: announcement.AuthorID,
|
|
|
|
|
|
IsPinned: announcement.IsPinned,
|
|
|
|
|
|
CreatedAt: dto.FormatTime(announcement.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return response, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetGroupMembers 获取群组成员列表
|
|
|
|
|
|
func (s *adminGroupServiceImpl) GetGroupMembers(ctx context.Context, groupID string, page, pageSize int) (*dto.AdminGroupMemberListResponse, error) {
|
|
|
|
|
|
// 先检查群组是否存在
|
|
|
|
|
|
_, err := s.groupRepo.GetByID(groupID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, errors.New("群组不存在")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
members, total, err := s.groupRepo.GetMembersWithUserInfo(groupID, page, pageSize)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
list := make([]*dto.AdminGroupMemberResponse, 0, len(members))
|
|
|
|
|
|
for _, member := range members {
|
|
|
|
|
|
item := &dto.AdminGroupMemberResponse{
|
|
|
|
|
|
ID: member.ID,
|
|
|
|
|
|
UserID: member.UserID,
|
|
|
|
|
|
Role: member.Role,
|
|
|
|
|
|
Nickname: member.Nickname,
|
|
|
|
|
|
Muted: member.Muted,
|
|
|
|
|
|
JoinedAt: dto.FormatTime(member.JoinTime),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if member.User != nil {
|
|
|
|
|
|
item.Username = member.User.Username
|
|
|
|
|
|
item.Nickname = member.User.Nickname
|
|
|
|
|
|
item.Avatar = member.User.Avatar
|
|
|
|
|
|
item.User = &dto.UserResponse{
|
|
|
|
|
|
ID: member.User.ID,
|
|
|
|
|
|
Username: member.User.Username,
|
|
|
|
|
|
Nickname: member.User.Nickname,
|
|
|
|
|
|
Avatar: member.User.Avatar,
|
|
|
|
|
|
CreatedAt: dto.FormatTime(member.User.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
list = append(list, item)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &dto.AdminGroupMemberListResponse{
|
|
|
|
|
|
List: list,
|
|
|
|
|
|
Total: total,
|
|
|
|
|
|
Page: page,
|
|
|
|
|
|
PageSize: pageSize,
|
|
|
|
|
|
}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DeleteGroup 解散群组
|
|
|
|
|
|
func (s *adminGroupServiceImpl) DeleteGroup(ctx context.Context, groupID string) error {
|
|
|
|
|
|
// 先检查群组是否存在
|
|
|
|
|
|
_, err := s.groupRepo.GetByID(groupID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return errors.New("群组不存在")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return s.groupRepo.Delete(groupID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateGroupStatus 更新群组状态
|
|
|
|
|
|
func (s *adminGroupServiceImpl) UpdateGroupStatus(ctx context.Context, groupID string, status string) (*dto.AdminGroupDetailResponse, error) {
|
|
|
|
|
|
// 先检查群组是否存在
|
|
|
|
|
|
group, err := s.groupRepo.GetByID(groupID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, errors.New("群组不存在")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证状态值
|
|
|
|
|
|
if status != "active" && status != "dissolved" {
|
|
|
|
|
|
return nil, errors.New("无效的状态值")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果状态是dissolved,则解散群组
|
|
|
|
|
|
if status == "dissolved" {
|
|
|
|
|
|
err = s.groupRepo.Delete(groupID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 更新群组状态
|
|
|
|
|
|
err = s.groupRepo.UpdateGroupStatus(groupID, status)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
// 重新获取群组信息
|
|
|
|
|
|
group, err = s.groupRepo.GetByID(groupID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建响应
|
|
|
|
|
|
response := &dto.AdminGroupDetailResponse{
|
|
|
|
|
|
ID: group.ID,
|
|
|
|
|
|
Name: group.Name,
|
|
|
|
|
|
Avatar: group.Avatar,
|
|
|
|
|
|
Description: group.Description,
|
|
|
|
|
|
OwnerID: group.OwnerID,
|
|
|
|
|
|
MemberCount: group.MemberCount,
|
|
|
|
|
|
MaxMembers: group.MaxMembers,
|
|
|
|
|
|
JoinType: int(group.JoinType),
|
|
|
|
|
|
MuteAll: group.MuteAll,
|
|
|
|
|
|
Status: status,
|
|
|
|
|
|
IsPublic: true,
|
|
|
|
|
|
CreatedAt: dto.FormatTime(group.CreatedAt),
|
|
|
|
|
|
UpdatedAt: dto.FormatTime(group.UpdatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取群主信息
|
|
|
|
|
|
if group.OwnerID != "" {
|
|
|
|
|
|
owner, err := s.userRepo.GetByID(group.OwnerID)
|
|
|
|
|
|
if err == nil && owner != nil {
|
|
|
|
|
|
response.Owner = &dto.UserResponse{
|
|
|
|
|
|
ID: owner.ID,
|
|
|
|
|
|
Username: owner.Username,
|
|
|
|
|
|
Nickname: owner.Nickname,
|
|
|
|
|
|
Avatar: owner.Avatar,
|
|
|
|
|
|
CreatedAt: dto.FormatTime(owner.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return response, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// RemoveMember 移除群组成员
|
|
|
|
|
|
func (s *adminGroupServiceImpl) RemoveMember(ctx context.Context, groupID string, userID string) error {
|
|
|
|
|
|
// 先检查群组是否存在
|
|
|
|
|
|
_, err := s.groupRepo.GetByID(groupID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return errors.New("群组不存在")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查用户是否是群成员
|
|
|
|
|
|
member, err := s.groupRepo.GetMember(groupID, userID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return errors.New("用户不是群组成员")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 不能移除群主
|
|
|
|
|
|
if member.Role == model.GroupRoleOwner {
|
|
|
|
|
|
return errors.New("不能移除群主")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return s.groupRepo.RemoveMember(groupID, userID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TransferOwner 转让群主
|
|
|
|
|
|
func (s *adminGroupServiceImpl) TransferOwner(ctx context.Context, groupID string, newOwnerID string) (*dto.AdminGroupDetailResponse, error) {
|
|
|
|
|
|
// 先检查群组是否存在
|
|
|
|
|
|
group, err := s.groupRepo.GetByID(groupID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, errors.New("群组不存在")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查新群主是否是群成员
|
|
|
|
|
|
newOwnerMember, err := s.groupRepo.GetMember(groupID, newOwnerID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, errors.New("新群主不是群组成员")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前群主信息
|
|
|
|
|
|
currentOwnerMember, err := s.groupRepo.GetMember(groupID, group.OwnerID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, errors.New("当前群主信息不存在")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
oldOwnerID := group.OwnerID
|
|
|
|
|
|
|
|
|
|
|
|
// 更新当前群主为普通成员
|
|
|
|
|
|
err = s.groupRepo.SetMemberRole(groupID, oldOwnerID, model.GroupRoleMember)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新新群主角色
|
|
|
|
|
|
err = s.groupRepo.SetMemberRole(groupID, newOwnerID, model.GroupRoleOwner)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
// 回滚
|
|
|
|
|
|
_ = s.groupRepo.SetMemberRole(groupID, oldOwnerID, model.GroupRoleOwner)
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新群组的OwnerID
|
|
|
|
|
|
group.OwnerID = newOwnerID
|
|
|
|
|
|
err = s.groupRepo.Update(group)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
// 回滚
|
|
|
|
|
|
_ = s.groupRepo.SetMemberRole(groupID, oldOwnerID, model.GroupRoleOwner)
|
|
|
|
|
|
_ = s.groupRepo.SetMemberRole(groupID, newOwnerID, newOwnerMember.Role)
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重新获取群组信息
|
|
|
|
|
|
group, err = s.groupRepo.GetByID(groupID)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建响应
|
|
|
|
|
|
response := &dto.AdminGroupDetailResponse{
|
|
|
|
|
|
ID: group.ID,
|
|
|
|
|
|
Name: group.Name,
|
|
|
|
|
|
Avatar: group.Avatar,
|
|
|
|
|
|
Description: group.Description,
|
|
|
|
|
|
OwnerID: group.OwnerID,
|
|
|
|
|
|
MemberCount: group.MemberCount,
|
|
|
|
|
|
MaxMembers: group.MaxMembers,
|
|
|
|
|
|
JoinType: int(group.JoinType),
|
|
|
|
|
|
MuteAll: group.MuteAll,
|
|
|
|
|
|
Status: "active",
|
|
|
|
|
|
IsPublic: true,
|
|
|
|
|
|
CreatedAt: dto.FormatTime(group.CreatedAt),
|
|
|
|
|
|
UpdatedAt: dto.FormatTime(group.UpdatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取新群主信息
|
|
|
|
|
|
if group.OwnerID != "" {
|
|
|
|
|
|
owner, err := s.userRepo.GetByID(group.OwnerID)
|
|
|
|
|
|
if err == nil && owner != nil {
|
|
|
|
|
|
response.Owner = &dto.UserResponse{
|
|
|
|
|
|
ID: owner.ID,
|
|
|
|
|
|
Username: owner.Username,
|
|
|
|
|
|
Nickname: owner.Nickname,
|
|
|
|
|
|
Avatar: owner.Avatar,
|
|
|
|
|
|
CreatedAt: dto.FormatTime(owner.CreatedAt),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_ = currentOwnerMember // 避免 unused variable 警告
|
|
|
|
|
|
|
|
|
|
|
|
return response, nil
|
|
|
|
|
|
}
|