feat(desktop): 支持桌面端余额账单配置

This commit is contained in:
chengcheng
2026-06-11 09:17:32 +08:00
parent e8df26da9b
commit bffd4ecb98
5 changed files with 76 additions and 1 deletions
@@ -773,10 +773,20 @@ WHERE reference_type = 'gateway_task'
Balance float64 `json:"balance"`
} `json:"primaryAccount"`
}
doJSON(t, server.URL, http.MethodGet, "/api/workspace/wallet", loginResponse.AccessToken, nil, http.StatusOK, &walletSummary)
doJSON(t, server.URL, http.MethodGet, "/api/workspace/wallet?currency=resource", loginResponse.AccessToken, nil, http.StatusOK, &walletSummary)
if walletSummary.PrimaryAccount.Currency != "resource" || !floatNear(walletSummary.PrimaryAccount.Balance, walletBalanceAfter) || len(walletSummary.Accounts) == 0 {
t.Fatalf("workspace wallet should expose current resource balance, got %+v want balance=%f", walletSummary, walletBalanceAfter)
}
var desktopConfig struct {
Billing struct {
GatewayBaseURL string `json:"gatewayBaseUrl"`
GatewayBillingPath string `json:"gatewayBillingPath"`
} `json:"billing"`
}
doJSON(t, server.URL, http.MethodGet, "/api/workspace/desktop-config", loginResponse.AccessToken, nil, http.StatusOK, &desktopConfig)
if desktopConfig.Billing.GatewayBillingPath != "/workspace/billing" || desktopConfig.Billing.GatewayBaseURL == "" {
t.Fatalf("desktop config should expose gateway billing route, got %+v", desktopConfig)
}
var walletTransactions struct {
Items []struct {
TransactionType string `json:"transactionType"`
@@ -0,0 +1,55 @@
package httpapi
import (
"net/http"
"strings"
)
type desktopBillingConfigResponse struct {
GatewayBaseURL string `json:"gatewayBaseUrl,omitempty"`
GatewayBillingPath string `json:"gatewayBillingPath"`
}
type desktopConfigResponse struct {
Billing desktopBillingConfigResponse `json:"billing"`
}
// getDesktopConfig godoc
// @Summary 获取桌面端配置
// @Description 返回桌面端需要的 Gateway Web 账单入口配置。
// @Tags workspace
// @Produce json
// @Security BearerAuth
// @Success 200 {object} desktopConfigResponse
// @Failure 401 {object} ErrorEnvelope
// @Router /api/workspace/desktop-config [get]
func (s *Server) getDesktopConfig(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, desktopConfigResponse{
Billing: desktopBillingConfigResponse{
GatewayBaseURL: firstNonEmpty(
strings.TrimRight(strings.TrimSpace(s.cfg.WebBaseURL), "/"),
strings.TrimRight(strings.TrimSpace(s.cfg.PublicBaseURL), "/"),
requestOrigin(r),
),
GatewayBillingPath: "/workspace/billing",
},
})
}
func requestOrigin(r *http.Request) string {
host := strings.TrimSpace(r.Host)
if host == "" {
return ""
}
proto := strings.TrimSpace(r.Header.Get("X-Forwarded-Proto"))
if proto == "" {
proto = "http"
}
if comma := strings.Index(proto, ","); comma >= 0 {
proto = strings.TrimSpace(proto[:comma])
}
if proto == "" {
proto = "http"
}
return proto + "://" + host
}
+1
View File
@@ -88,6 +88,7 @@ func NewServerWithContext(ctx context.Context, cfg config.Config, db *store.Stor
mux.Handle("PATCH /api/v1/api-keys/{apiKeyID}/disable", server.auth.Require(auth.PermissionBasic, http.HandlerFunc(server.disableAPIKey)))
mux.Handle("DELETE /api/v1/api-keys/{apiKeyID}", server.auth.Require(auth.PermissionBasic, http.HandlerFunc(server.deleteAPIKey)))
mux.Handle("GET /api/playground/api-keys", server.auth.Require(auth.PermissionBasic, http.HandlerFunc(server.listPlayableAPIKeys)))
mux.Handle("GET /api/workspace/desktop-config", server.auth.Require(auth.PermissionBasic, http.HandlerFunc(server.getDesktopConfig)))
mux.Handle("GET /api/workspace/user-groups", server.auth.Require(auth.PermissionBasic, http.HandlerFunc(server.listCurrentUserGroups)))
mux.Handle("GET /api/workspace/wallet", server.auth.Require(auth.PermissionBasic, http.HandlerFunc(server.getWallet)))
mux.Handle("GET /api/workspace/wallet/transactions", server.auth.Require(auth.PermissionBasic, http.HandlerFunc(server.listWalletTransactions)))