From 2071758a2b24cc21521ec1888df7ddf60065e88f Mon Sep 17 00:00:00 2001
From: zhangqian <zhangqian@123.com>
Date: 星期六, 28 十月 2023 15:33:09 +0800
Subject: [PATCH] 新增用户信息更新管理器,定时更新活跃用户的详情,当用户访问系统的时候更新活跃时间,定时清理非活跃用户

---
 service/user.go            |   14 ++
 proto/user.proto           |    2 
 proto/user/user.pb.go      |   92 ++++++++------
 middleware/refresh_user.go |  131 +++++++++++++++++++++
 middleware/user.go         |   19 ++-
 service/lru.go             |   15 +
 middleware/jwt.go          |    5 
 model/user.go              |   22 +++
 main.go                    |   12 +-
 9 files changed, 251 insertions(+), 61 deletions(-)

diff --git a/main.go b/main.go
index 462350f..558c976 100644
--- a/main.go
+++ b/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()
diff --git a/middleware/jwt.go b/middleware/jwt.go
index 6fae7ea..eac7b32 100644
--- a/middleware/jwt.go
+++ b/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)
diff --git a/middleware/refresh_user.go b/middleware/refresh_user.go
new file mode 100644
index 0000000..22db40c
--- /dev/null
+++ b/middleware/refresh_user.go
@@ -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
+		}
+	}
+}
diff --git a/middleware/user.go b/middleware/user.go
index 1f0caac..8a1a2b7 100644
--- a/middleware/user.go
+++ b/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())
diff --git a/model/user.go b/model/user.go
index 318a24b..93e8c3d 100644
--- a/model/user.go
+++ b/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
+}
diff --git a/proto/user.proto b/proto/user.proto
index 50e32f3..83a93cc 100644
--- a/proto/user.proto
+++ b/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 {
diff --git a/proto/user/user.pb.go b/proto/user/user.pb.go
index 399d3aa..7ea96ff 100644
--- a/proto/user/user.pb.go
+++ b/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 (
diff --git a/service/lru.go b/service/lru.go
index a09d09f..5a8f73d 100644
--- a/service/lru.go
+++ b/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
diff --git a/service/user.go b/service/user.go
index 3f40330..182b747 100644
--- a/service/user.go
+++ b/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
+}

--
Gitblit v1.8.0