新增用户信息更新管理器,定时更新活跃用户的详情,当用户访问系统的时候更新活跃时间,定时清理非活跃用户
1个文件已添加
8个文件已修改
312 ■■■■ 已修改文件
main.go 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
middleware/jwt.go 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
middleware/refresh_user.go 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
middleware/user.go 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
model/user.go 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
proto/user.proto 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
proto/user/user.pb.go 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/lru.go 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/user.go 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main.go
@@ -46,13 +46,12 @@
        WriteTimeout: 5 * time.Second,
    }
    go v1.InitProductServiceConn()
    go middleware.InitUserConn()
    go v1.InitCodeServiceConn()
    v1.InitProductServiceConn()
    middleware.InitUserConn()
    v1.InitCodeServiceConn()
    //c := cron.New()
    //c.AddFunc("@every 15s", service.SyncUserInfo) // 每15秒同步一次
    //c.Start()
    middleware.InitRefreshUserManager(5, 5, 3600)
    middleware.RunRefreshUser() ///定时对活跃用户更新用户详情
    logx.Error(server.ListenAndServe().Error())
}
@@ -62,6 +61,7 @@
    signal.Notify(quit, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGTERM)
    <-quit
    middleware.StopRefreshUser()
    v1.CloseProductServiceConn()
    v1.CloseCodeServiceConn()
    middleware.CloseUserConn()
middleware/jwt.go
@@ -107,9 +107,12 @@
        }
        userInfo := service.GetUserBaseCache(claims.UserId)
        if userInfo == nil {
            SyncUserInfo(claims.UserId)
            SyncUserInfo([]string{claims.UserId})
            userInfo = service.GetUserBaseCache(claims.UserId)
        }
        SetActiveTime(claims.UserId)
        claims.CrmUserId = userInfo.UserId
        claims.NickName = userInfo.NickName
        c.Set("claims", claims)
middleware/refresh_user.go
New file
@@ -0,0 +1,131 @@
package middleware
import (
    "context"
    "fmt"
    "sync"
    "sync/atomic"
    "time"
)
// RefreshUserManager 定时拉取活跃用户的信息(包含下属id)
type RefreshUserManager struct {
    RunFlag                   int32
    StartRemoveUserFlag       int32
    StartRefreshUserFlag      int32
    Users                     map[string]*CurrentActiveUser
    mu                        sync.RWMutex
    ctx                       context.Context
    expireSecond              int64
    intervalRemoveUserMinute  int
    intervalRefreshUserMinute int
    cancel                    func()
}
type CurrentActiveUser struct {
    UserID         string
    lastActiveTime int64
}
var defaultRefreshUserManager *RefreshUserManager
func InitRefreshUserManager(intervalRefreshUserMinute, intervalRemoveMinute int, expireSecond int64) {
    if intervalRefreshUserMinute == 0 {
        intervalRefreshUserMinute = 5
    }
    if intervalRemoveMinute > 0 && expireSecond == 0 {
        expireSecond = int64(intervalRemoveMinute * 60 * 12)
    }
    ctx, cancel := context.WithCancel(context.Background())
    defaultRefreshUserManager = &RefreshUserManager{
        expireSecond:              expireSecond,
        intervalRemoveUserMinute:  intervalRemoveMinute,
        intervalRefreshUserMinute: intervalRefreshUserMinute,
        ctx:                       ctx,
        cancel:                    cancel,
    }
}
func RunRefreshUser() {
    if !atomic.CompareAndSwapInt32(&defaultRefreshUserManager.RunFlag, 0, 1) {
        return
    }
    go defaultRefreshUserManager.refreshUserInfo()
    go defaultRefreshUserManager.removeInActiveUser()
}
func StopRefreshUser() {
    defaultRefreshUserManager.cancel()
}
func SetActiveTime(userID string) {
    defaultRefreshUserManager.setActiveTime(userID)
}
// RefreshActiveTime 更新用户活跃时间
func (r *RefreshUserManager) setActiveTime(userID string) {
    r.mu.Lock()
    defer r.mu.Unlock()
    if r.Users[userID] == nil {
        r.Users[userID] = &CurrentActiveUser{
            UserID:         userID,
            lastActiveTime: time.Now().Unix(),
        }
    } else {
        r.Users[userID].lastActiveTime = time.Now().Unix()
    }
}
func (r *RefreshUserManager) removeInActiveUser() {
    if !atomic.CompareAndSwapInt32(&r.StartRemoveUserFlag, 0, 1) {
        return
    }
    if r.intervalRemoveUserMinute == 0 { //不清理
        return
    }
    ticker := time.NewTicker(time.Minute * time.Duration(r.intervalRemoveUserMinute))
    for {
        select {
        case <-ticker.C:
            nowTs := time.Now().Unix()
            fmt.Println("it is time to RemoveInActiveUser:", nowTs)
            r.mu.RLock()
            for userID, user := range r.Users {
                if nowTs-user.lastActiveTime > r.expireSecond {
                    r.mu.Lock()
                    delete(r.Users, userID)
                    r.mu.Unlock()
                }
            }
            r.mu.RUnlock()
        case <-r.ctx.Done():
            fmt.Println("stop RemoveInActiveUser.")
            return
        }
    }
}
func (r *RefreshUserManager) refreshUserInfo() {
    if !atomic.CompareAndSwapInt32(&r.StartRefreshUserFlag, 0, 1) {
        return
    }
    ticker := time.NewTicker(time.Minute * time.Duration(r.intervalRefreshUserMinute))
    for {
        select {
        case <-ticker.C:
            nowTs := time.Now().Unix()
            fmt.Println("it is time to RefreshUserInfo:", nowTs)
            r.mu.RLock()
            userIds := make([]string, len(r.Users))
            for userID := range r.Users {
                userIds = append(userIds, userID)
            }
            r.mu.RUnlock()
            if len(userIds) != 0 {
                SyncUserInfo(userIds)
            }
        case <-r.ctx.Done():
            fmt.Println("stop RefreshUserInfo.")
            return
        }
    }
}
middleware/user.go
@@ -10,6 +10,7 @@
    "fmt"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials/insecure"
    "strings"
    "time"
)
@@ -59,10 +60,13 @@
    return rsp.Result
}
func SyncUserInfo(uuid string) {
func SyncUserInfo(uuid []string) {
    cli := user.NewUserServiceClient(userConn)
    var users = []*user.User{
        {Uuid: uuid},
    var users []*user.User
    for _, id := range uuid {
        users = append(users, &user.User{
            Uuid: id,
        })
    }
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
@@ -76,10 +80,11 @@
    for _, member := range r.List {
        err = model.NewUserSearch(nil).Upsert(model.User{
            UUID:     member.Uuid,
            Username: member.Username,
            UserType: constvar.UserType(member.Usertype),
            NickName: member.Nickname,
            UUID:       member.Uuid,
            Username:   member.Username,
            UserType:   constvar.UserType(member.Usertype),
            NickName:   member.Nickname,
            SubUserIds: strings.Join(member.SubUserIds, ","),
        })
        if err != nil {
            logx.Errorf("sync user error: %v", err.Error())
model/user.go
@@ -27,6 +27,7 @@
        MenuIds      []uint            `json:"menuIds" gorm:"-"`                              // 菜单ID列表
        AuthorityId  uint              `json:"authorityId" gorm:"default:888;comment:用户角色ID"` // 用户角色ID
        Authority    Authority         `json:"authority" gorm:"foreignKey:AuthorityId"`
        SubUserIds   string            `json:"subUserIds" gorm:"sub_user_ids"` //下属员工用户id,用逗号分开
        gorm.Model   `json:"-"`
    }
@@ -283,10 +284,29 @@
    if err := db.Clauses(clause.OnConflict{
        Columns:   []clause.Column{{Name: "uuid"}},
        DoUpdates: clause.AssignmentColumns([]string{"uuid", "username", "user_type", "nick_name"}),
        DoUpdates: clause.AssignmentColumns([]string{"username", "user_type", "nick_name", "sub_user_ids"}),
    }).Create(&record).Error; err != nil {
        return fmt.Errorf("first or create err: %v, record: %+v", err, record)
    }
    return nil
}
type IdPair struct {
    ID   int    `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"`
    UUID string `json:"uuid" gorm:"unique;type:varchar(255);comment:用户ID"`
}
func (slf *UserSearch) UUID2CrmUserId(userIds []string) ([]*IdPair, error) {
    var (
        records = make([]*IdPair, 0)
        db      = slf.build()
    )
    db = db.Where("uuid in ?", userIds)
    if err := db.Find(&records).Error; err != nil {
        return records, fmt.Errorf("find all err: %v", err)
    }
    return records, nil
}
proto/user.proto
@@ -14,7 +14,7 @@
  string username = 2;
  int32 usertype = 3;
  string nickname = 4;
  // ... other fields
  repeated string sub_user_ids = 5;
}
message UserRequest {
proto/user/user.pb.go
@@ -25,10 +25,11 @@
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields
    Uuid     string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"`
    Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
    Usertype int32  `protobuf:"varint,3,opt,name=usertype,proto3" json:"usertype,omitempty"`
    Nickname string `protobuf:"bytes,4,opt,name=nickname,proto3" json:"nickname,omitempty"` // ... other fields
    Uuid       string   `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"`
    Username   string   `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
    Usertype   int32    `protobuf:"varint,3,opt,name=usertype,proto3" json:"usertype,omitempty"`
    Nickname   string   `protobuf:"bytes,4,opt,name=nickname,proto3" json:"nickname,omitempty"`
    SubUserIds []string `protobuf:"bytes,5,rep,name=sub_user_ids,json=subUserIds,proto3" json:"sub_user_ids,omitempty"`
}
func (x *User) Reset() {
@@ -89,6 +90,13 @@
        return x.Nickname
    }
    return ""
}
func (x *User) GetSubUserIds() []string {
    if x != nil {
        return x.SubUserIds
    }
    return nil
}
type UserRequest struct {
@@ -331,43 +339,45 @@
var file_user_proto_rawDesc = []byte{
    0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x75, 0x73,
    0x65, 0x72, 0x22, 0x6e, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75,
    0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x1a,
    0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
    0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73,
    0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75, 0x73,
    0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61,
    0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61,
    0x6d, 0x65, 0x22, 0x2f, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
    0x74, 0x12, 0x20, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
    0x32, 0x0a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73,
    0x65, 0x72, 0x73, 0x22, 0x72, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f,
    0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
    0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
    0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
    0x65, 0x12, 0x1e, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
    0x0a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x4c, 0x69, 0x73,
    0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
    0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x48, 0x0a, 0x0c, 0x43, 0x68, 0x65, 0x63, 0x6b,
    0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x50, 0x61,
    0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x69, 0x50, 0x61, 0x74,
    0x68, 0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x18,
    0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70,
    0x65, 0x22, 0x55, 0x0a, 0x0d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
    0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
    0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
    0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
    0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
    0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x32, 0x7a, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72,
    0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x53, 0x79, 0x6e, 0x63, 0x55,
    0x73, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52,
    0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73,
    0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x0d, 0x55, 0x73,
    0x65, 0x72, 0x4d, 0x65, 0x6e, 0x75, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x12, 0x2e, 0x75, 0x73,
    0x65, 0x72, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
    0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70,
    0x6f, 0x6e, 0x73, 0x65, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x62, 0x06,
    0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
    0x65, 0x72, 0x22, 0x90, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x75,
    0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12,
    0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
    0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75,
    0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x75,
    0x73, 0x65, 0x72, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e,
    0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x6e,
    0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f,
    0x69, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x75, 0x62, 0x55, 0x73,
    0x65, 0x72, 0x49, 0x64, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71,
    0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20,
    0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52,
    0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x72, 0x0a, 0x0c, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65,
    0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01,
    0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,
    0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73,
    0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x03,
    0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04,
    0x4c, 0x69, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x04, 0x20,
    0x01, 0x28, 0x03, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x48, 0x0a, 0x0c, 0x43, 0x68,
    0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x70,
    0x69, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x70, 0x69,
    0x50, 0x61, 0x74, 0x68, 0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x79,
    0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
    0x54, 0x79, 0x70, 0x65, 0x22, 0x55, 0x0a, 0x0d, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73,
    0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20,
    0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73,
    0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73,
    0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20,
    0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x32, 0x7a, 0x0a, 0x0b, 0x55,
    0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x53, 0x79,
    0x6e, 0x63, 0x55, 0x73, 0x65, 0x72, 0x12, 0x11, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73,
    0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x75, 0x73, 0x65, 0x72,
    0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a,
    0x0d, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x65, 0x6e, 0x75, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x12,
    0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65,
    0x73, 0x74, 0x1a, 0x13, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52,
    0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x75, 0x73, 0x65,
    0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
service/lru.go
@@ -2,12 +2,14 @@
import (
    "github.com/hashicorp/golang-lru/v2/expirable"
    "strings"
    "time"
)
type UserBaseInfo struct {
    UserId   int
    NickName string
    UserId     int
    NickName   string
    SubUserIds []int
}
var userCache *expirable.LRU[string, *UserBaseInfo]
@@ -25,9 +27,14 @@
        if err != nil {
            return nil
        }
        subIds, _, err := userService.UUID2CrmUserId(strings.Split(userRecord.SubUserIds, ","))
        if err != nil {
            return nil
        }
        baseInfo := &UserBaseInfo{
            UserId:   userRecord.ID,
            NickName: userRecord.NickName,
            UserId:     userRecord.ID,
            NickName:   userRecord.NickName,
            SubUserIds: subIds,
        }
        SetUserBaseCache(adminUserId, baseInfo)
        return baseInfo
service/user.go
@@ -93,3 +93,17 @@
func (userService *UserService) GetUserList() (userList []*model.User, err error) {
    return model.NewUserSearch(nil).FindAll()
}
func (userService *UserService) UUID2CrmUserId(uuids []string) (crmUserIds []int, m map[string]int, err error) {
    idPairs, err := model.NewUserSearch(nil).UUID2CrmUserId(uuids)
    if err != nil {
        return
    }
    crmUserIds = make([]int, 0, len(idPairs))
    m = make(map[string]int, len(idPairs))
    for _, idPair := range idPairs {
        crmUserIds = append(crmUserIds, idPair.ID)
        m[idPair.UUID] = idPair.ID
    }
    return
}