// Package service 承载管理后台业务逻辑层,编排 dto、mysqldao、redisdao 与 pkg 能力。 // // 约定: // - 每个业务域一个 Service 结构体,NewXxxService() 构造,内部持有所需 DAO。 // - 方法统一返回 (*dto.XxxResponse, *errcode.Error),将底层 error 映射为语义化错误。 // - redis 未命中返回 redis.Nil,按缓存未命中处理,不视为错误。 // - 所有管理写操作在 service 层做权限与状态校验(AuthZ)。 package service import ( "context" "errors" "time" "git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/internal/middleware" "git.lzcwy.cn/zhengchiliu/zt-closet-manage-backend/pkg/errcode" "github.com/google/uuid" "github.com/redis/go-redis/v9" "gorm.io/gorm" ) // isNotFound 判断 gorm 是否为「记录不存在」。 func isNotFound(err error) bool { return errors.Is(err, gorm.ErrRecordNotFound) } // isCacheMiss 判断 redis 是否为「未命中」。 func isCacheMiss(err error) bool { return errors.Is(err, redis.Nil) } // 分页默认值。 const ( defaultPage = 1 defaultPageSize = 10 maxPageSize = 50 ) // normalizePage 规整分页参数,返回可直接用于 DAO 的 page/pageSize。 func normalizePage(page, pageSize int) (int, int) { if page <= 0 { page = defaultPage } if pageSize <= 0 { pageSize = defaultPageSize } if pageSize > maxPageSize { pageSize = maxPageSize } return page, pageSize } // nowUnix 当前秒级时间戳。 func nowUnix() int64 { return time.Now().Unix() } // todayStartUnix 返回本地时区今日 0 点的秒级时间戳。 func todayStartUnix() int64 { now := time.Now() start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) return start.Unix() } // todayStatDate 返回本地时区今日的 YYYYMMDD 整数(user_daily_usages 统计日期)。 func todayStatDate() int64 { now := time.Now() return int64(now.Year()*10000 + int(now.Month())*100 + now.Day()) } // genUUID 生成新的 UUID 字符串。 func genUUID() string { return uuid.NewString() } // requireAdminID 从 context 取管理员 ID(由中间件注入),缺失返回未授权错误。 func requireAdminID(ctx context.Context) (int64, *errcode.Error) { adminID, ok := middleware.GetAdminID(ctx) if !ok || adminID <= 0 { return 0, errcode.Unauthorized } return adminID, nil }