package user import ( "context" "strconv" "strings" modelUser "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" ) type GetFamilyListLogic struct { ctx context.Context svcCtx *svc.ServiceContext logger.Logger } func NewGetFamilyListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFamilyListLogic { return &GetFamilyListLogic{ ctx: ctx, svcCtx: svcCtx, Logger: logger.WithContext(ctx), } } func (l *GetFamilyListLogic) GetFamilyList(req *types.GetFamilyListRequest) (*types.GetFamilyListResponse, error) { page := req.Page size := req.Size if page <= 0 { page = 1 } if size <= 0 { size = 20 } if size > 200 { size = 200 } query := l.svcCtx.DB.WithContext(l.ctx). Model(&modelUser.UserFamily{}). Where("user_family.deleted_at IS NULL") if req.OwnerUserId != nil { query = query.Where("user_family.owner_user_id = ?", *req.OwnerUserId) } if req.FamilyId != nil { query = query.Where("user_family.id = ?", *req.FamilyId) } if req.UserId != nil { query = query.Where( "EXISTS (SELECT 1 FROM user_family_member ufm WHERE ufm.family_id = user_family.id AND ufm.deleted_at IS NULL AND ufm.status = ? AND ufm.user_id = ?)", modelUser.FamilyMemberActive, *req.UserId, ) } if statusValue, ok := normalizeFamilyStatusInput(req.Status); ok { query = query.Where("user_family.status = ?", statusValue) } keyword := strings.TrimSpace(req.Keyword) if keyword != "" { keywordLike := "%" + keyword + "%" query = query.Where( "(CAST(user_family.id AS CHAR) LIKE ? OR CAST(user_family.owner_user_id AS CHAR) LIKE ? OR "+ "EXISTS (SELECT 1 FROM user_auth_methods owner_auth WHERE owner_auth.user_id = user_family.owner_user_id AND owner_auth.deleted_at IS NULL AND owner_auth.auth_identifier LIKE ?) OR "+ "EXISTS (SELECT 1 FROM user_family_member keyword_member JOIN user_auth_methods keyword_auth ON keyword_auth.user_id = keyword_member.user_id AND keyword_auth.deleted_at IS NULL WHERE keyword_member.family_id = user_family.id AND keyword_member.deleted_at IS NULL AND keyword_auth.auth_identifier LIKE ?))", keywordLike, keywordLike, keywordLike, keywordLike, ) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "count family list failed") } var families []modelUser.UserFamily if err := query.Order("user_family.id DESC"). Limit(size). Offset((page - 1) * size). Find(&families).Error; err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query family list failed") } if len(families) == 0 { return &types.GetFamilyListResponse{ Total: total, List: []types.FamilySummary{}, }, nil } ownerIDs := make([]int64, 0, len(families)) familyIDs := make([]int64, 0, len(families)) for _, family := range families { ownerIDs = append(ownerIDs, family.OwnerUserId) familyIDs = append(familyIDs, family.Id) } identifierMap, identifierErr := findUserIdentifiers(l.ctx, l.svcCtx.DB, ownerIDs) if identifierErr != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query family owner identifiers failed") } type familyCount struct { FamilyId int64 Count int64 } var counts []familyCount if err := l.svcCtx.DB.WithContext(l.ctx). Table("user_family_member"). Select("family_id, COUNT(1) as count"). Where("family_id IN ? AND deleted_at IS NULL AND status = ?", familyIDs, modelUser.FamilyMemberActive). Group("family_id"). Scan(&counts).Error; err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query family member counts failed") } countMap := make(map[int64]int64, len(counts)) for _, count := range counts { countMap[count.FamilyId] = count.Count } list := make([]types.FamilySummary, 0, len(families)) for _, family := range families { ownerInfo := identifierMap[family.OwnerUserId] ownerIdentifier := ownerInfo.Identifier ownerAuthType := ownerInfo.AuthType if ownerIdentifier == "" { ownerIdentifier = strconv.FormatInt(family.OwnerUserId, 10) } list = append(list, types.FamilySummary{ FamilyId: family.Id, OwnerUserId: family.OwnerUserId, OwnerIdentifier: ownerIdentifier, OwnerAuthType: ownerAuthType, Status: mapFamilyStatus(family.Status), ActiveMemberCount: countMap[family.Id], MaxMembers: family.MaxMembers, CreatedAt: family.CreatedAt.Unix(), UpdatedAt: family.UpdatedAt.Unix(), }) } return &types.GetFamilyListResponse{ Total: total, List: list, }, nil }