From 6be442bfdeda6bbae3c7b08c1ec7cd854ba3970f Mon Sep 17 00:00:00 2001 From: qhd <1766646056@qq.com> Date: Mon, 17 Aug 2026 17:49:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=A7=9F=E6=88=B7?= =?UTF-8?q?=E4=BD=99=E9=A2=9D=E5=86=85=E9=83=A8=E6=9F=A5=E8=AF=A2=E4=B8=8E?= =?UTF-8?q?=E6=89=A3=E5=87=8F=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/system/tenant.go | 21 +++++++ .../app/system/controller/tenant_balance.go | 58 +++++++++++++++++++ internal/app/system/router/router.go | 6 ++ 3 files changed, 85 insertions(+) create mode 100644 internal/app/system/controller/tenant_balance.go diff --git a/api/v1/system/tenant.go b/api/v1/system/tenant.go index 0d63b98..16ca3d9 100644 --- a/api/v1/system/tenant.go +++ b/api/v1/system/tenant.go @@ -58,6 +58,27 @@ type TenantEditReq struct { type TenantEditRes struct { } +// TenantBalanceReq 查询租户余额(内部接口,model-gateway 调用,不走 gftoken/Auth) +type TenantBalanceReq struct { + g.Meta `path:"/tenant/balance" tags:"租户余额(内部)" method:"get" summary:"查询租户余额"` + TenantId uint64 `p:"tenantId" v:"required#租户id不能为空"` +} + +type TenantBalanceRes struct { + g.Meta `mime:"application/json"` + Tenant *entity.Tenant `json:"tenant"` +} + +// TenantDeductReq 扣减租户余额(内部接口,model-gateway 调用;surplus 传负值即扣减) +type TenantDeductReq struct { + g.Meta `path:"/tenant/deduct" tags:"租户余额(内部)" method:"post" summary:"扣减租户余额"` + Id int64 `p:"id" v:"required#租户id不能为空"` + Surplus float64 `p:"surplus"` +} + +type TenantDeductRes struct { +} + // GetTenantDetailsByIdsReq 获取多个租户详情请求参数 type GetTenantDetailsByIdsReq struct { g.Meta `path:"/tenant/getTenantDetailsByIds" tags:"租户管理" method:"get" summary:"获取多个租户详情"` diff --git a/internal/app/system/controller/tenant_balance.go b/internal/app/system/controller/tenant_balance.go new file mode 100644 index 0000000..602b518 --- /dev/null +++ b/internal/app/system/controller/tenant_balance.go @@ -0,0 +1,58 @@ +package controller + +import ( + "context" + + "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/frame/g" + "github.com/gogf/gf/v2/util/gconv" + "github.com/tiger1103/gfast/v3/api/v1/system" + "github.com/tiger1103/gfast/v3/internal/app/system/service" +) + +var ( + TenantBalance = tenantBalanceController{} +) + +type tenantBalanceController struct{} + +// callerUser 归属校验只取租户字段(调用方经 X-User-Info 头携带用户信息) +type callerUser struct { + TenantId uint64 `json:"tenantId"` +} + +// callerTenantId 从 X-User-Info 头解析调用方租户 id;头缺失/解析失败返回 0 +func (c *tenantBalanceController) callerTenantId(ctx context.Context) uint64 { + r := g.RequestFromCtx(ctx) + if r == nil { + return 0 + } + userInfoHeader := r.Header.Get("X-User-Info") + if userInfoHeader == "" { + return 0 + } + var caller callerUser + if err := gconv.Struct(userInfoHeader, &caller); err != nil { + return 0 + } + return caller.TenantId +} + +// Balance 查询租户余额(内部接口,供 model-gateway 调用;调用方只能查询自己所属租户) +func (c *tenantBalanceController) Balance(ctx context.Context, req *system.TenantBalanceReq) (res *system.TenantBalanceRes, err error) { + if caller := c.callerTenantId(ctx); caller == 0 || caller != req.TenantId { + return nil, gerror.New("无权查询该租户余额") + } + res = new(system.TenantBalanceRes) + res.Tenant, err = service.Tenant().GetTenantDetails(ctx, req.TenantId) + return +} + +// Deduct 扣减租户余额(内部接口;surplus 传负值走 Edit 的 Counter 增量即扣减;调用方只能扣减自己所属租户) +func (c *tenantBalanceController) Deduct(ctx context.Context, req *system.TenantDeductReq) (res *system.TenantDeductRes, err error) { + if caller := c.callerTenantId(ctx); caller == 0 || caller != uint64(req.Id) { + return nil, gerror.New("无权扣减该租户余额") + } + err = service.Tenant().Edit(ctx, &system.TenantEditReq{Id: req.Id, Surplus: req.Surplus}) + return +} diff --git a/internal/app/system/router/router.go b/internal/app/system/router/router.go index 8234b4e..3567443 100644 --- a/internal/app/system/router/router.go +++ b/internal/app/system/router/router.go @@ -56,4 +56,10 @@ func (router *Router) BindController(ctx context.Context, group *ghttp.RouterGro panic(err) } }) + // 内部租户余额接口:不挂 gftoken/Auth(model-gateway 内部调用,查/扣租户余额不依赖用户管理员权限) + group.Group("/pub", func(group *ghttp.RouterGroup) { + group.Bind( + controller.TenantBalance, + ) + }) }