115 lines
3.8 KiB
Go
115 lines
3.8 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"model-gateway/model/dto"
|
||
|
||
commonHttp "gitea.redpowerfuture.com/red-future/common/http"
|
||
"gitea.redpowerfuture.com/red-future/common/oss"
|
||
"gitea.redpowerfuture.com/red-future/common/utils"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/util/gconv"
|
||
)
|
||
|
||
// DeductBalanceReq 扣减余额请求
|
||
type DeductBalanceReq struct {
|
||
Id uint64 `json:"id"`
|
||
Surplus float64 `json:"surplus"`
|
||
}
|
||
|
||
// DeductBalance 扣减租户余额。走 admin-go 内部接口 /pub/tenant/deduct(无 gftoken/Auth,供 model-gateway 内部调用)。
|
||
// admin-go 的 tenant/edit 对 surplus 走 gdb.Counter 增量(正加负减),故扣减须传负值;调用方在本次未产生费用(cost<=0)时应跳过。
|
||
func DeductBalance(ctx context.Context, tenantId uint64, amount float64) error {
|
||
apiURL := "admin-go/api/v1/pub/tenant/deduct"
|
||
headers := setCtxHeader(ctx)
|
||
|
||
body := DeductBalanceReq{
|
||
Id: tenantId,
|
||
Surplus: -amount,
|
||
}
|
||
jsonData, _ := json.Marshal(body)
|
||
|
||
var resp struct{}
|
||
err := commonHttp.Post(ctx, apiURL, headers, &resp, jsonData)
|
||
if err != nil {
|
||
g.Log().Warningf(ctx, "[扣减余额] 失败 tenantId=%d amount=%.6f err=%v", tenantId, amount, err)
|
||
return err
|
||
}
|
||
g.Log().Infof(ctx, "[扣减余额] 成功 tenantId=%d amount=%.6f", tenantId, amount)
|
||
return nil
|
||
}
|
||
|
||
// TenantSurplusResp 租户余额返回
|
||
type TenantSurplusResp struct {
|
||
Tenant struct {
|
||
Surplus float64 `json:"surplus"`
|
||
} `json:"tenant"`
|
||
}
|
||
|
||
// GetTenantSurplus 获取租户余额(走 admin-go 内部接口 /pub/tenant/balance,无 gftoken/Auth)
|
||
func GetTenantSurplus(ctx context.Context, tenantId uint64) (float64, error) {
|
||
apiURL := fmt.Sprintf("admin-go/api/v1/pub/tenant/balance?tenantId=%d", tenantId)
|
||
headers := setCtxHeader(ctx)
|
||
|
||
var resp TenantSurplusResp
|
||
err := commonHttp.Get(ctx, apiURL, headers, &resp, nil)
|
||
if err != nil {
|
||
g.Log().Warningf(ctx, "[获取余额] 失败 tenantId=%d err=%v", tenantId, err)
|
||
return 0, err
|
||
}
|
||
return resp.Tenant.Surplus, nil
|
||
}
|
||
|
||
// IsSuperAdmin 调用admin-go服务检查是否是管理员
|
||
func IsSuperAdmin(ctx context.Context) (res bool, err error) {
|
||
headers := setCtxHeader(ctx)
|
||
var r = make(map[string]bool)
|
||
if err = commonHttp.Get(ctx, "admin-go/api/v1/system/user/checkIsSuperAdmin", headers, &r); err != nil {
|
||
return false, err
|
||
}
|
||
return r["isSuperAdmin"], err
|
||
}
|
||
|
||
// Upload 上传文件到 OSS。统一走 common/oss(multipart field=file、X-User-Info 三态注入与旧 setCtxHeader 等价)。
|
||
func Upload(ctx context.Context, req *dto.UploadFileBytesReq) (*dto.UploadFileBytesRes, error) {
|
||
res, err := oss.UploadFileBytes(ctx, req.FileName, req.FileBytes)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return &dto.UploadFileBytesRes{
|
||
FileURL: res.FileURL,
|
||
FileSize: res.FileSize,
|
||
FileName: res.FileName,
|
||
FileFormat: res.FileFormat,
|
||
FileAddressPrefix: res.FileAddressPrefix,
|
||
}, nil
|
||
}
|
||
|
||
// setCtxHeader 构造调用方请求头透传(X-User-Info 三态注入):
|
||
// 1. 透传 HTTP 请求头(含 Authorization/X-User-Info)
|
||
// 2. ctx 无请求头时,用任务体注入的 user(异步任务 Creator/TenantId)生成 X-User-Info
|
||
// 3. 仍为空时,解析调用方 token 得到用户生成 X-User-Info(直连场景归属校验)
|
||
func setCtxHeader(ctx context.Context) map[string]string {
|
||
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 headers["X-User-Info"] == "" {
|
||
if user := ctx.Value("user"); !g.IsNil(user) {
|
||
headers["X-User-Info"] = gconv.String(user)
|
||
}
|
||
}
|
||
if headers["X-User-Info"] == "" {
|
||
if user, err := utils.GetUserInfo(ctx); err == nil && user != nil {
|
||
headers["X-User-Info"] = gconv.String(user)
|
||
}
|
||
}
|
||
return headers
|
||
}
|