/* * @desc:模块租户关系处理 * @company:云南奇讯科技有限公司 * @Author: system * @Date: 2026/1/6 */ package moduleTenant import ( "context" "fmt" "time" "gitea.com/red-future/common/beans" "gitea.com/red-future/common/http" "gitea.com/red-future/common/utils" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv" "github.com/tiger1103/gfast/v3/api/v1/system" "github.com/tiger1103/gfast/v3/internal/app/system/consts" "github.com/tiger1103/gfast/v3/internal/app/system/dao" "github.com/tiger1103/gfast/v3/internal/app/system/model/do" "github.com/tiger1103/gfast/v3/internal/app/system/model/entity" "github.com/tiger1103/gfast/v3/internal/app/system/service" "github.com/tiger1103/gfast/v3/library/liberr" ) func init() { service.RegisterModuleTenant(New()) } type sModuleTenant struct { } func New() *sModuleTenant { return &sModuleTenant{} } // Add 添加模块租户关系 func (s *sModuleTenant) Add(ctx context.Context, req *system.ModuleTenantAddReq) (err error) { err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { err = g.Try(ctx, func(ctx context.Context) { // 获取用户信息 var getUserInfo *beans.User getUserInfo, err = utils.GetUserInfo(ctx) liberr.ErrIsNil(ctx, err, "获取用户信息失败") // 获取sku信息 assetSukRes := new(system.AssetSku) // 获取当前请求的 headers 并传递到下游 headers := make(map[string]string) if r := g.RequestFromCtx(ctx); r != nil { for k, v := range r.Request.Header { if len(v) > 0 { headers[k] = v[0] } } } if err = http.Get(ctx, "asset/sku/getAssetSkuModule", headers, &assetSukRes, "id", req.AssetSkuId, ); err != nil { return } liberr.ErrIsNil(ctx, err, "获取资产sku信息失败") if assetSukRes.ExpireAt != nil { liberr.ErrIsNil(ctx, err, "sku到期时间不能为空") } // 获取模块key var moduleKey string // 遍历 map 的所有键值对 for key, value := range beans.ModuleAssetId { if value == assetSukRes.AssetId { moduleKey = key break } } // 检查是否已存在相同的模块租户关系 var moduleTenant *entity.ModuleTenant moduleTenant, err = s.GetByModuleKeyAndTenantId(ctx, moduleKey, gconv.Uint64(getUserInfo.TenantId)) liberr.ErrIsNil(ctx, err, "检查模块租户关系失败") if moduleTenant != nil { now := gtime.Now() if moduleTenant.ExpireAt != nil && !moduleTenant.ExpireAt.Before(now) { // 使用原到期时间 + SKU到期时间 duration := assetSukRes.ExpireAt.Sub(gtime.Now()) assetSukRes.ExpireAt = moduleTenant.ExpireAt.Add(duration) } // 更新模块租户关系 _, err = dao.ModuleTenant.Ctx(ctx).TX(tx).WherePri(moduleTenant.Id).Update(do.ModuleTenant{ UpdateBy: getUserInfo.UserName, ExpireAt: assetSukRes.ExpireAt, }) return } // 设置认证状态 certificationStatus := consts.CertificationStatusPass if req.TenantModuleType == beans.TenantModuleTypeSupplier { certificationStatus = consts.CertificationStatusUnverified } // 添加模块租户关系 _, err = dao.ModuleTenant.Ctx(ctx).TX(tx).InsertAndGetId(do.ModuleTenant{ CreateBy: getUserInfo.UserName, UpdateBy: getUserInfo.UserName, ModuleKey: moduleKey, AssetId: assetSukRes.AssetId, AssetSkuId: req.AssetSkuId, TenantId: getUserInfo.TenantId, TenantModuleType: req.TenantModuleType, CertificationStatus: certificationStatus, ExpireAt: assetSukRes.ExpireAt, }) liberr.ErrIsNil(ctx, err, "添加模块租户关系失败") // 设置缓存 _, err = s.AddRedisByTenantId(ctx, &system.AddRedisByTenantIdReq{ TenantId: getUserInfo.TenantId, }) liberr.ErrIsNil(ctx, err, "设置缓存失败") }) return err }) return } // Check 检查模块开通状态 func (s *sModuleTenant) Check(ctx context.Context, req *system.ModuleTenantCheckReq) (res *system.ModuleTenantCheckRes, err error) { err = g.Try(ctx, func(ctx context.Context) { res = new(system.ModuleTenantCheckRes) // 查询模块租户关系 moduleTenant, err := s.GetByModuleKeyAndTenantId(ctx, req.ModuleKey, req.TenantId) liberr.ErrIsNil(ctx, err, "查询模块租户关系失败") // 判断状态 if g.IsEmpty(moduleTenant) { // 没有记录,未开通 res.Message = "您未开通此功能模块,请开通后再使用" res.Status = false } else { _, err = s.AddRedisByTenantId(ctx, &system.AddRedisByTenantIdReq{ TenantId: req.TenantId, }) liberr.ErrIsNil(ctx, err, "设置缓存失败") // 有记录,检查是否到期 now := gtime.Now() if moduleTenant.ExpireAt != nil && moduleTenant.ExpireAt.Before(now) { res.Message = "功能模块已到期,请续期后再使用" res.Status = false } else { res.Status = true if moduleTenant.CertificationStatus == consts.CertificationStatusPass { res.Message = "已开通" res.CertificationStatus = true } else { keyValue := consts.GetCertificationStatusKeyValue(moduleTenant.CertificationStatus) res.Message = fmt.Sprintf("功能模块认证状态:%s", keyValue.Value) res.CertificationStatus = false } } } }) return } // GetByModuleKeyAndTenantId 根据模块Key和租户ID获取模块租户关系 func (s *sModuleTenant) GetByModuleKeyAndTenantId(ctx context.Context, moduleKey string, tenantId uint64) (moduleTenant *entity.ModuleTenant, err error) { err = g.Try(ctx, func(ctx context.Context) { err = dao.ModuleTenant.Ctx(ctx). Where(dao.ModuleTenant.Columns().ModuleKey, moduleKey). Where(dao.ModuleTenant.Columns().TenantId, tenantId). Scan(&moduleTenant) liberr.ErrIsNil(ctx, err, "获取模块租户关系失败") }) return } // AddRedisByTenantId 根据租户ID获取模块租户关系存到redis func (s *sModuleTenant) AddRedisByTenantId(ctx context.Context, req *system.AddRedisByTenantIdReq) (res *system.AddRedisByTenantIdRes, err error) { res = new(system.AddRedisByTenantIdRes) //从数据库获取 err = dao.ModuleTenant.Ctx(ctx). Where(dao.ModuleTenant.Columns().TenantId, req.TenantId). Scan(&res.List) liberr.ErrIsNil(ctx, err, "获取模块租户关系失败") if !g.IsEmpty(res.List) { err = g.Redis().SetEX(ctx, fmt.Sprintf("module_tenant:tenantId-%d", gconv.Int(req.TenantId)), res.List, gconv.Int64(time.Minute*1)) liberr.ErrIsNil(ctx, err, "设置缓存失败") } return }