hi-server/internal/logic/admin/user/getUserListLogic.go
shanshanzhong 282e1e4087
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 7m26s
deviceno
2026-03-17 09:12:56 -07:00

207 lines
6.2 KiB
Go

package user
import (
"context"
"fmt"
"strings"
"time"
logicCommon "github.com/perfect-panel/server/internal/logic/common"
"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/phone"
"github.com/perfect-panel/server/pkg/tool"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
)
type GetUserListLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logger.Logger
}
func NewGetUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserListLogic {
return &GetUserListLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logger.WithContext(ctx),
}
}
func (l *GetUserListLogic) GetUserList(req *types.GetUserListRequest) (*types.GetUserListResponse, error) {
list, total, err := l.svcCtx.UserModel.QueryPageList(l.ctx, req.Page, req.Size, &user.UserFilterParams{
UserId: req.UserId,
Search: req.Search,
Unscoped: req.Unscoped,
SubscribeId: req.SubscribeId,
UserSubscribeId: req.UserSubscribeId,
ShortCode: req.ShortCode,
DeviceId: req.DeviceId,
FamilyJoined: req.FamilyJoined,
FamilyStatus: req.FamilyStatus,
FamilyOwnerUserId: req.FamilyOwnerUserId,
FamilyId: req.FamilyId,
Order: req.SortOrder,
})
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "GetUserListLogic failed: %v", err.Error())
}
referCodes := make([]string, 0, len(list))
for _, item := range list {
referCode := strings.TrimSpace(item.ReferCode)
if referCode == "" {
continue
}
referCodes = append(referCodes, referCode)
}
inviteLinkMap := logicCommon.NewInviteLinkResolver(l.ctx, l.svcCtx).ResolveInviteLinksBatch(referCodes, 8, 3, 1500*time.Millisecond)
// Batch fetch active subscriptions
userIds := make([]int64, 0, len(list))
for _, u := range list {
userIds = append(userIds, u.Id)
}
activeSubs, err := l.svcCtx.UserModel.FindActiveSubscribesByUserIds(l.ctx, userIds)
if err != nil {
// Log error but continue
l.Logger.Error("FindActiveSubscribesByUserIds failed", logger.Field("error", err.Error()))
}
type familyRelation struct {
UserId int64
FamilyId int64
Role uint8
FamilyStatus uint8
OwnerUserId int64
MaxMembers int64
}
relationMap := map[int64]familyRelation{}
familyIds := make([]int64, 0)
if len(userIds) > 0 {
var relations []familyRelation
relationErr := l.svcCtx.DB.WithContext(l.ctx).
Table("user_family_member").
Select("user_family_member.user_id, user_family_member.family_id, user_family_member.role, user_family.status as family_status, user_family.owner_user_id, user_family.max_members").
Joins("JOIN user_family ON user_family.id = user_family_member.family_id AND user_family.deleted_at IS NULL").
Where("user_family_member.user_id IN ? AND user_family_member.deleted_at IS NULL AND user_family_member.status = ?", userIds, user.FamilyMemberActive).
Scan(&relations).Error
if relationErr != nil {
l.Logger.Error("query family relations failed", logger.Field("error", relationErr.Error()))
}
familyIdSet := make(map[int64]struct{}, len(relations))
for _, relation := range relations {
if _, exists := relationMap[relation.UserId]; !exists {
relationMap[relation.UserId] = relation
}
if _, ok := familyIdSet[relation.FamilyId]; ok {
continue
}
familyIdSet[relation.FamilyId] = struct{}{}
familyIds = append(familyIds, relation.FamilyId)
}
}
type familyCount struct {
FamilyId int64
Count int64
}
familyCountMap := map[int64]int64{}
if len(familyIds) > 0 {
var counts []familyCount
countErr := l.svcCtx.DB.WithContext(l.ctx).
Table("user_family_member").
Select("family_id, COUNT(1) as count").
Where("family_id IN ? AND status = ? AND deleted_at IS NULL", familyIds, user.FamilyMemberActive).
Group("family_id").
Scan(&counts).Error
if countErr != nil {
l.Logger.Error("query family member count failed", logger.Field("error", countErr.Error()))
}
for _, count := range counts {
familyCountMap[count.FamilyId] = count.Count
}
}
userRespList := make([]types.User, 0, len(list))
for _, item := range list {
var u types.User
tool.DeepCopy(&u, item)
// Set LastLoginTime
if item.LastLoginTime != nil {
u.LastLoginTime = item.LastLoginTime.Unix()
}
// Set MemberStatus and update LastLoginTime from traffic
if activeSubs != nil {
if info, ok := activeSubs[item.Id]; ok {
u.MemberStatus = info.MemberStatus
u.PurchasedPackage = info.PurchasedPackage
if info.LastTrafficAt != nil {
trafficTime := info.LastTrafficAt.Unix()
if trafficTime > u.LastLoginTime {
u.LastLoginTime = trafficTime
}
}
}
}
// 处理 AuthMethods
authMethods := make([]types.UserAuthMethod, len(u.AuthMethods)) // 直接创建目标 slice
for i, method := range u.AuthMethods {
tool.DeepCopy(&authMethods[i], method)
if method.AuthType == "mobile" {
authMethods[i].AuthIdentifier = phone.FormatToInternational(method.AuthIdentifier)
}
}
u.AuthMethods = authMethods
// 填充 DeviceID
for i, d := range item.UserDevices {
if i < len(u.UserDevices) {
u.UserDevices[i].DeviceNo = tool.DeviceIdToHash(d.Id)
}
}
if relation, ok := relationMap[item.Id]; ok {
u.FamilyJoined = true
u.FamilyId = relation.FamilyId
u.FamilyRole = relation.Role
u.FamilyOwnerUserId = relation.OwnerUserId
u.FamilyMaxMembers = relation.MaxMembers
u.FamilyMemberCount = familyCountMap[relation.FamilyId]
switch relation.FamilyStatus {
case user.FamilyStatusActive:
u.FamilyStatus = "active"
default:
u.FamilyStatus = "disabled"
}
switch relation.Role {
case user.FamilyRoleOwner:
u.FamilyRoleName = "owner"
case user.FamilyRoleMember:
u.FamilyRoleName = "member"
default:
u.FamilyRoleName = fmt.Sprintf("role_%d", relation.Role)
}
}
if referCode := strings.TrimSpace(item.ReferCode); referCode != "" {
u.ShareLink = inviteLinkMap[referCode]
}
userRespList = append(userRespList, u)
}
return &types.GetUserListResponse{
Total: total,
List: userRespList,
}, nil
}