538 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			538 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package mid
 | ||
| 
 | ||
| //import (
 | ||
| //	"context"
 | ||
| //	"encoding/json"
 | ||
| //	"errors"
 | ||
| //	"fmt"
 | ||
| //	"log"
 | ||
| //	"net/http"
 | ||
| //	"strconv"
 | ||
| //	"sync"
 | ||
| //	"time"
 | ||
| //
 | ||
| //	"management/internal/erpserver/model/dto"
 | ||
| //	v1 "management/internal/erpserver/service/v1"
 | ||
| //	"management/internal/pkg/know"
 | ||
| //	"management/internal/pkg/session"
 | ||
| //
 | ||
| //	"github.com/allegro/bigcache/v3"
 | ||
| //)
 | ||
| //
 | ||
| //var publicRoutes = map[string]bool{
 | ||
| //	"/home.html":          true,
 | ||
| //	"/dashboard":          true,
 | ||
| //	"/system/menus":       true,
 | ||
| //	"/upload/img":         true,
 | ||
| //	"/upload/file":        true,
 | ||
| //	"/upload/multi_files": true,
 | ||
| //	"/pear.json":          true,
 | ||
| //	"/logout":             true,
 | ||
| //}
 | ||
| //
 | ||
| //// MenuCacheEntry 菜单缓存条目
 | ||
| //type MenuCacheEntry struct {
 | ||
| //	Data      map[string]*dto.OwnerMenuDto `json:"data"`
 | ||
| //	Timestamp int64                        `json:"timestamp"`
 | ||
| //	Version   int64                        `json:"version"`
 | ||
| //}
 | ||
| //
 | ||
| //// CacheStats 缓存统计信息
 | ||
| //type CacheStats struct {
 | ||
| //	mu               sync.RWMutex
 | ||
| //	Hits             int64
 | ||
| //	Misses           int64
 | ||
| //	Errors           int64
 | ||
| //	RefreshCount     int64
 | ||
| //	AsyncRefreshHits int64
 | ||
| //	LastRefreshTime  time.Time
 | ||
| //}
 | ||
| //
 | ||
| //// GetHitRate 获取命中率
 | ||
| //func (cs *CacheStats) GetHitRate() float64 {
 | ||
| //	cs.mu.RLock()
 | ||
| //	defer cs.mu.RUnlock()
 | ||
| //
 | ||
| //	total := cs.Hits + cs.Misses
 | ||
| //	if total == 0 {
 | ||
| //		return 0
 | ||
| //	}
 | ||
| //	return float64(cs.Hits) / float64(total) * 100
 | ||
| //}
 | ||
| //
 | ||
| //// MenuCacheManager BigCache菜单缓存管理器
 | ||
| //type MenuCacheManager struct {
 | ||
| //	cache         *bigcache.BigCache
 | ||
| //	refreshTTL    time.Duration
 | ||
| //	stats         *CacheStats
 | ||
| //	mu            sync.RWMutex
 | ||
| //	refreshing    map[int64]bool
 | ||
| //	stopCh        chan struct{}
 | ||
| //	monitorTicker *time.Ticker
 | ||
| //}
 | ||
| //
 | ||
| //// NewMenuCacheManager 创建菜单缓存管理器
 | ||
| //func NewMenuCacheManager(ttl time.Duration) (*MenuCacheManager, error) {
 | ||
| //	config := bigcache.DefaultConfig(ttl)
 | ||
| //
 | ||
| //	// 生产环境优化配置
 | ||
| //	config.Shards = 256                  // 分片数,减少锁竞争
 | ||
| //	config.MaxEntriesInWindow = 10000    // 窗口内最大条目数
 | ||
| //	config.MaxEntrySize = 1024 * 50      // 最大条目50KB
 | ||
| //	config.HardMaxCacheSize = 512        // 最大缓存512MB
 | ||
| //	config.StatsEnabled = true           // 启用统计
 | ||
| //	config.Verbose = false               // 关闭详细日志
 | ||
| //	config.CleanWindow = 5 * time.Minute // 清理窗口
 | ||
| //
 | ||
| //	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
 | ||
| //	defer cancel()
 | ||
| //
 | ||
| //	cache, err := bigcache.New(ctx, config)
 | ||
| //	if err != nil {
 | ||
| //		return nil, fmt.Errorf("failed to create BigCache: %w", err)
 | ||
| //	}
 | ||
| //
 | ||
| //	manager := &MenuCacheManager{
 | ||
| //		cache:         cache,
 | ||
| //		refreshTTL:    time.Duration(float64(ttl) * 0.8), // 80%时间后开始刷新
 | ||
| //		stats:         &CacheStats{},
 | ||
| //		refreshing:    make(map[int64]bool),
 | ||
| //		stopCh:        make(chan struct{}),
 | ||
| //		monitorTicker: time.NewTicker(time.Minute), // 每分钟监控一次
 | ||
| //	}
 | ||
| //
 | ||
| //	// 启动监控协程
 | ||
| //	go manager.monitor()
 | ||
| //
 | ||
| //	return manager, nil
 | ||
| //}
 | ||
| //
 | ||
| //// Get 获取缓存数据
 | ||
| //func (mcm *MenuCacheManager) Get(roleID int32) (map[string]*dto.OwnerMenuDto, bool, bool) {
 | ||
| //	key := mcm.makeKey(roleID)
 | ||
| //
 | ||
| //	data, err := mcm.cache.Get(key)
 | ||
| //	if err != nil {
 | ||
| //		if !errors.Is(err, bigcache.ErrEntryNotFound) {
 | ||
| //			mcm.recordError()
 | ||
| //			log.Printf("BigCache get error for roleID %d: %v", roleID, err)
 | ||
| //		}
 | ||
| //		mcm.recordMiss()
 | ||
| //		return nil, false, false
 | ||
| //	}
 | ||
| //
 | ||
| //	// 反序列化
 | ||
| //	var entry MenuCacheEntry
 | ||
| //	if err := json.Unmarshal(data, &entry); err != nil {
 | ||
| //		mcm.recordError()
 | ||
| //		log.Printf("Failed to unmarshal cache entry for roleID %d: %v", roleID, err)
 | ||
| //		mcm.recordMiss()
 | ||
| //		return nil, false, false
 | ||
| //	}
 | ||
| //
 | ||
| //	mcm.recordHit()
 | ||
| //
 | ||
| //	// 检查是否需要刷新
 | ||
| //	needRefresh := time.Since(time.Unix(entry.Timestamp, 0)) > mcm.refreshTTL
 | ||
| //
 | ||
| //	return entry.Data, true, needRefresh
 | ||
| //}
 | ||
| //
 | ||
| //// Set 设置缓存数据
 | ||
| //func (mcm *MenuCacheManager) Set(roleID int32, data map[string]*dto.OwnerMenuDto) error {
 | ||
| //	key := mcm.makeKey(roleID)
 | ||
| //
 | ||
| //	entry := MenuCacheEntry{
 | ||
| //		Data:      data,
 | ||
| //		Timestamp: time.Now().Unix(),
 | ||
| //		Version:   time.Now().UnixNano(),
 | ||
| //	}
 | ||
| //
 | ||
| //	// 序列化
 | ||
| //	entryData, err := json.Marshal(entry)
 | ||
| //	if err != nil {
 | ||
| //		mcm.recordError()
 | ||
| //		return fmt.Errorf("failed to marshal cache entry: %w", err)
 | ||
| //	}
 | ||
| //
 | ||
| //	// 存储到BigCache
 | ||
| //	err = mcm.cache.Set(key, entryData)
 | ||
| //	if err != nil {
 | ||
| //		mcm.recordError()
 | ||
| //		return fmt.Errorf("failed to set cache: %w", err)
 | ||
| //	}
 | ||
| //
 | ||
| //	return nil
 | ||
| //}
 | ||
| //
 | ||
| //// Delete 删除缓存数据
 | ||
| //func (mcm *MenuCacheManager) Delete(roleID int32) error {
 | ||
| //	key := mcm.makeKey(roleID)
 | ||
| //	err := mcm.cache.Delete(key)
 | ||
| //	if err != nil && !errors.Is(err, bigcache.ErrEntryNotFound) {
 | ||
| //		mcm.recordError()
 | ||
| //		return fmt.Errorf("failed to delete cache: %w", err)
 | ||
| //	}
 | ||
| //	return nil
 | ||
| //}
 | ||
| //
 | ||
| //// makeKey 生成缓存key
 | ||
| //func (mcm *MenuCacheManager) makeKey(roleID int32) string {
 | ||
| //	return "menu:role:" + strconv.Itoa(int(roleID))
 | ||
| //}
 | ||
| //
 | ||
| //// GetStats 获取统计信息
 | ||
| //func (mcm *MenuCacheManager) GetStats() *CacheStats {
 | ||
| //	mcm.stats.mu.RLock()
 | ||
| //	defer mcm.stats.mu.RUnlock()
 | ||
| //
 | ||
| //	// 复制统计数据
 | ||
| //	stats := *mcm.stats
 | ||
| //	return &stats
 | ||
| //}
 | ||
| //
 | ||
| //// GetBigCacheStats 获取BigCache原生统计
 | ||
| //func (mcm *MenuCacheManager) GetBigCacheStats() bigcache.Stats {
 | ||
| //	return mcm.cache.Stats()
 | ||
| //}
 | ||
| //
 | ||
| //// recordHit 记录命中
 | ||
| //func (mcm *MenuCacheManager) recordHit() {
 | ||
| //	mcm.stats.mu.Lock()
 | ||
| //	mcm.stats.Hits++
 | ||
| //	mcm.stats.mu.Unlock()
 | ||
| //}
 | ||
| //
 | ||
| //// recordMiss 记录未命中
 | ||
| //func (mcm *MenuCacheManager) recordMiss() {
 | ||
| //	mcm.stats.mu.Lock()
 | ||
| //	mcm.stats.Misses++
 | ||
| //	mcm.stats.mu.Unlock()
 | ||
| //}
 | ||
| //
 | ||
| //// recordError 记录错误
 | ||
| //func (mcm *MenuCacheManager) recordError() {
 | ||
| //	mcm.stats.mu.Lock()
 | ||
| //	mcm.stats.Errors++
 | ||
| //	mcm.stats.mu.Unlock()
 | ||
| //}
 | ||
| //
 | ||
| //// recordRefresh 记录刷新
 | ||
| //func (mcm *MenuCacheManager) recordRefresh() {
 | ||
| //	mcm.stats.mu.Lock()
 | ||
| //	mcm.stats.RefreshCount++
 | ||
| //	mcm.stats.LastRefreshTime = time.Now()
 | ||
| //	mcm.stats.mu.Unlock()
 | ||
| //}
 | ||
| //
 | ||
| //// recordAsyncRefreshHit 记录异步刷新命中
 | ||
| //func (mcm *MenuCacheManager) recordAsyncRefreshHit() {
 | ||
| //	mcm.stats.mu.Lock()
 | ||
| //	mcm.stats.AsyncRefreshHits++
 | ||
| //	mcm.stats.mu.Unlock()
 | ||
| //}
 | ||
| //
 | ||
| //// monitor 监控协程
 | ||
| //func (mcm *MenuCacheManager) monitor() {
 | ||
| //	for {
 | ||
| //		select {
 | ||
| //		case <-mcm.monitorTicker.C:
 | ||
| //			mcm.logStats()
 | ||
| //		case <-mcm.stopCh:
 | ||
| //			mcm.monitorTicker.Stop()
 | ||
| //			return
 | ||
| //		}
 | ||
| //	}
 | ||
| //}
 | ||
| //
 | ||
| //// logStats 记录统计信息
 | ||
| //func (mcm *MenuCacheManager) logStats() {
 | ||
| //	stats := mcm.GetStats()
 | ||
| //	bigCacheStats := mcm.GetBigCacheStats()
 | ||
| //
 | ||
| //	log.Printf("MenuCache Stats - Hits: %d, Misses: %d, Errors: %d, HitRate: %.2f%%, "+
 | ||
| //		"RefreshCount: %d, AsyncRefreshHits: %d, BigCache Hits: %d, BigCache Misses: %d",
 | ||
| //		stats.Hits, stats.Misses, stats.Errors, stats.GetHitRate(),
 | ||
| //		stats.RefreshCount, stats.AsyncRefreshHits,
 | ||
| //		bigCacheStats.Hits, bigCacheStats.Misses)
 | ||
| //}
 | ||
| //
 | ||
| //// Close 关闭缓存管理器
 | ||
| //func (mcm *MenuCacheManager) Close() error {
 | ||
| //	close(mcm.stopCh)
 | ||
| //	return mcm.cache.Close()
 | ||
| //}
 | ||
| //
 | ||
| //// CachedMenuService 带BigCache的菜单服务
 | ||
| //type CachedMenuService struct {
 | ||
| //	menuService v1.MenuService
 | ||
| //	cache       *MenuCacheManager
 | ||
| //	mu          sync.RWMutex
 | ||
| //	refreshing  map[int32]bool
 | ||
| //}
 | ||
| //
 | ||
| //// NewCachedMenuService 创建带缓存的菜单服务
 | ||
| //func NewCachedMenuService(menuService v1.MenuService, cache *MenuCacheManager) *CachedMenuService {
 | ||
| //	return &CachedMenuService{
 | ||
| //		menuService: menuService,
 | ||
| //		cache:       cache,
 | ||
| //		refreshing:  make(map[int32]bool),
 | ||
| //	}
 | ||
| //}
 | ||
| //
 | ||
| //// ListByRoleIDToMap 获取菜单数据(带BigCache缓存)
 | ||
| //func (cms *CachedMenuService) ListByRoleIDToMap(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) {
 | ||
| //	// 尝试从缓存获取
 | ||
| //	data, hit, needRefresh := cms.cache.Get(roleID)
 | ||
| //	if hit {
 | ||
| //		// 如果需要刷新且当前没有在刷新中,启动异步刷新
 | ||
| //		if needRefresh && !cms.isRefreshing(roleID) {
 | ||
| //			go cms.asyncRefresh(roleID)
 | ||
| //		}
 | ||
| //		return data, nil
 | ||
| //	}
 | ||
| //
 | ||
| //	// 缓存未命中,同步获取
 | ||
| //	return cms.loadAndCache(ctx, roleID)
 | ||
| //}
 | ||
| //
 | ||
| //// loadAndCache 加载数据并缓存
 | ||
| //func (cms *CachedMenuService) loadAndCache(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) {
 | ||
| //	// 防止并发重复加载
 | ||
| //	cms.mu.Lock()
 | ||
| //	if cms.refreshing[roleID] {
 | ||
| //		cms.mu.Unlock()
 | ||
| //		// 等待一小段时间后重试缓存
 | ||
| //		time.Sleep(time.Millisecond * 5)
 | ||
| //		if data, hit, _ := cms.cache.Get(roleID); hit {
 | ||
| //			return data, nil
 | ||
| //		}
 | ||
| //		// 重试失败,继续加载
 | ||
| //		cms.mu.Lock()
 | ||
| //	}
 | ||
| //	cms.refreshing[roleID] = true
 | ||
| //	cms.mu.Unlock()
 | ||
| //
 | ||
| //	defer func() {
 | ||
| //		cms.mu.Lock()
 | ||
| //		delete(cms.refreshing, roleID)
 | ||
| //		cms.mu.Unlock()
 | ||
| //	}()
 | ||
| //
 | ||
| //	// 从原始服务获取数据
 | ||
| //	data, err := cms.menuService.ListByRoleIDToMap(ctx, roleID)
 | ||
| //	if err != nil {
 | ||
| //		return nil, err
 | ||
| //	}
 | ||
| //
 | ||
| //	// 缓存数据
 | ||
| //	if cacheErr := cms.cache.Set(roleID, data); cacheErr != nil {
 | ||
| //		log.Printf("Failed to cache menu data for roleID %d: %v", roleID, cacheErr)
 | ||
| //		// 缓存失败不影响业务逻辑,继续返回数据
 | ||
| //	}
 | ||
| //
 | ||
| //	return data, nil
 | ||
| //}
 | ||
| //
 | ||
| //// asyncRefresh 异步刷新缓存
 | ||
| //func (cms *CachedMenuService) asyncRefresh(roleID int32) {
 | ||
| //	// 检查是否已在刷新中
 | ||
| //	if cms.isRefreshing(roleID) {
 | ||
| //		return
 | ||
| //	}
 | ||
| //
 | ||
| //	// 使用背景上下文
 | ||
| //	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
 | ||
| //	defer cancel()
 | ||
| //
 | ||
| //	_, err := cms.loadAndCache(ctx, roleID)
 | ||
| //	if err != nil {
 | ||
| //		log.Printf("Async refresh menu cache failed for roleID %d: %v", roleID, err)
 | ||
| //	} else {
 | ||
| //		cms.cache.recordRefresh()
 | ||
| //		cms.cache.recordAsyncRefreshHit()
 | ||
| //	}
 | ||
| //}
 | ||
| //
 | ||
| //// isRefreshing 检查是否正在刷新
 | ||
| //func (cms *CachedMenuService) isRefreshing(roleID int32) bool {
 | ||
| //	cms.mu.RLock()
 | ||
| //	refreshing := cms.refreshing[roleID]
 | ||
| //	cms.mu.RUnlock()
 | ||
| //	return refreshing
 | ||
| //}
 | ||
| //
 | ||
| //// InvalidateRole 使指定角色缓存失效
 | ||
| //func (cms *CachedMenuService) InvalidateRole(roleID int32) error {
 | ||
| //	return cms.cache.Delete(roleID)
 | ||
| //}
 | ||
| //
 | ||
| //// GetCacheStats 获取缓存统计
 | ||
| //func (cms *CachedMenuService) GetCacheStats() *CacheStats {
 | ||
| //	return cms.cache.GetStats()
 | ||
| //}
 | ||
| //
 | ||
| //// 全局实例
 | ||
| //var (
 | ||
| //	menuCacheManager *MenuCacheManager
 | ||
| //	cachedMenuSvc    *CachedMenuService
 | ||
| //	cacheInitOnce    sync.Once
 | ||
| //	cacheInitErr     error
 | ||
| //)
 | ||
| //
 | ||
| //// InitMenuCache 初始化菜单缓存
 | ||
| //func InitMenuCache(menuService v1.MenuService) error {
 | ||
| //	cacheInitOnce.Do(func() {
 | ||
| //		// 缓存TTL设置为15分钟
 | ||
| //		manager, err := NewMenuCacheManager(15 * time.Minute)
 | ||
| //		if err != nil {
 | ||
| //			cacheInitErr = fmt.Errorf("failed to initialize menu cache: %w", err)
 | ||
| //			return
 | ||
| //		}
 | ||
| //
 | ||
| //		menuCacheManager = manager
 | ||
| //		cachedMenuSvc = NewCachedMenuService(menuService, manager)
 | ||
| //
 | ||
| //		log.Println("MenuCache initialized successfully with BigCache")
 | ||
| //	})
 | ||
| //
 | ||
| //	return cacheInitErr
 | ||
| //}
 | ||
| //
 | ||
| //// GetCachedMenuService 获取缓存菜单服务
 | ||
| //func GetCachedMenuService() *CachedMenuService {
 | ||
| //	return cachedMenuSvc
 | ||
| //}
 | ||
| //
 | ||
| //// GetMenuCacheManager 获取缓存管理器
 | ||
| //func GetMenuCacheManager() *MenuCacheManager {
 | ||
| //	return menuCacheManager
 | ||
| //}
 | ||
| //
 | ||
| //// CloseMenuCache 关闭菜单缓存
 | ||
| //func CloseMenuCache() error {
 | ||
| //	if menuCacheManager != nil {
 | ||
| //		return menuCacheManager.Close()
 | ||
| //	}
 | ||
| //	return nil
 | ||
| //}
 | ||
| //
 | ||
| //// Authorize 修改后的授权中间件
 | ||
| //func Authorize(
 | ||
| //	sess session.Manager,
 | ||
| //	menuService v1.MenuService,
 | ||
| //) func(http.Handler) http.Handler {
 | ||
| //	// 初始化缓存
 | ||
| //	if err := InitMenuCache(menuService); err != nil {
 | ||
| //		log.Printf("Failed to initialize menu cache: %v", err)
 | ||
| //		// 缓存初始化失败,降级到原始服务
 | ||
| //		return func(next http.Handler) http.Handler {
 | ||
| //			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | ||
| //				ctx := r.Context()
 | ||
| //				path := r.URL.Path
 | ||
| //
 | ||
| //				// 登陆检查
 | ||
| //				n := time.Now()
 | ||
| //				user, err := sess.GetUser(ctx, know.StoreName)
 | ||
| //				if err != nil || user.ID == 0 {
 | ||
| //					http.Redirect(w, r, "/", http.StatusFound)
 | ||
| //					return
 | ||
| //				}
 | ||
| //				log.Printf("scs get user: %s", time.Since(n).String())
 | ||
| //
 | ||
| //				// 公共路由放行
 | ||
| //				if publicRoutes[path] {
 | ||
| //					ctx = setUser(ctx, user)
 | ||
| //					next.ServeHTTP(w, r.WithContext(ctx))
 | ||
| //					return
 | ||
| //				}
 | ||
| //
 | ||
| //				n1 := time.Now()
 | ||
| //				// 权限检查 - 使用原始服务
 | ||
| //				menus, err := menuService.ListByRoleIDToMap(ctx, user.RoleID)
 | ||
| //				if err != nil || !hasPermission(menus, path) {
 | ||
| //					http.Error(w, "Forbidden", http.StatusForbidden)
 | ||
| //					return
 | ||
| //				}
 | ||
| //				log.Printf("listByRoleIDToMap (fallback): %s", time.Since(n1).String())
 | ||
| //
 | ||
| //				n2 := time.Now()
 | ||
| //				cur := getCurrentMenus(menus, path)
 | ||
| //				log.Printf("getCurrentMenus: %s", time.Since(n2).String())
 | ||
| //
 | ||
| //				ctx = setUser(ctx, user)
 | ||
| //				ctx = setCurMenus(ctx, cur)
 | ||
| //				next.ServeHTTP(w, r.WithContext(ctx))
 | ||
| //			})
 | ||
| //		}
 | ||
| //	}
 | ||
| //
 | ||
| //	return func(next http.Handler) http.Handler {
 | ||
| //		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | ||
| //			ctx := r.Context()
 | ||
| //			path := r.URL.Path
 | ||
| //
 | ||
| //			// 登陆检查
 | ||
| //			n := time.Now()
 | ||
| //			user, err := sess.GetUser(ctx, know.StoreName)
 | ||
| //			if err != nil || user.ID == 0 {
 | ||
| //				http.Redirect(w, r, "/", http.StatusFound)
 | ||
| //				return
 | ||
| //			}
 | ||
| //			log.Printf("scs get user: %s", time.Since(n).String())
 | ||
| //
 | ||
| //			// 公共路由放行
 | ||
| //			if publicRoutes[path] {
 | ||
| //				ctx = setUser(ctx, user)
 | ||
| //				next.ServeHTTP(w, r.WithContext(ctx))
 | ||
| //				return
 | ||
| //			}
 | ||
| //
 | ||
| //			n1 := time.Now()
 | ||
| //			// 权限检查 - 使用BigCache缓存服务
 | ||
| //			menus, err := GetCachedMenuService().ListByRoleIDToMap(ctx, user.RoleID)
 | ||
| //			if err != nil || !hasPermission(menus, path) {
 | ||
| //				http.Error(w, "Forbidden", http.StatusForbidden)
 | ||
| //				return
 | ||
| //			}
 | ||
| //			log.Printf("listByRoleIDToMap (BigCache): %s", time.Since(n1).String())
 | ||
| //
 | ||
| //			n2 := time.Now()
 | ||
| //			cur := getCurrentMenus(menus, path)
 | ||
| //			log.Printf("getCurrentMenus: %s", time.Since(n2).String())
 | ||
| //
 | ||
| //			ctx = setUser(ctx, user)
 | ||
| //			ctx = setCurMenus(ctx, cur)
 | ||
| //			next.ServeHTTP(w, r.WithContext(ctx))
 | ||
| //		})
 | ||
| //	}
 | ||
| //}
 | ||
| //
 | ||
| //func hasPermission(menus map[string]*dto.OwnerMenuDto, path string) bool {
 | ||
| //	_, ok := menus[path]
 | ||
| //	return ok
 | ||
| //}
 | ||
| //
 | ||
| //func getCurrentMenus(data map[string]*dto.OwnerMenuDto, path string) []dto.OwnerMenuDto {
 | ||
| //	var res []dto.OwnerMenuDto
 | ||
| //
 | ||
| //	menu, ok := data[path]
 | ||
| //	if !ok {
 | ||
| //		return res
 | ||
| //	}
 | ||
| //
 | ||
| //	for _, item := range data {
 | ||
| //		if menu.IsList {
 | ||
| //			if item.ParentID == menu.ID || item.ID == menu.ID {
 | ||
| //				res = append(res, *item)
 | ||
| //			}
 | ||
| //		} else {
 | ||
| //			if item.ParentID == menu.ParentID {
 | ||
| //				res = append(res, *item)
 | ||
| //			}
 | ||
| //		}
 | ||
| //	}
 | ||
| //
 | ||
| //	return res
 | ||
| //}
 |