feat(heicode-self): complete quota contract for all display types (#14 review)

Returns raw quota + the full conversion params (quota_per_unit, quota_display_type,
usd_exchange_rate) AND server-computed display_quota / display_used_quota, so the
desktop client renders correctly in USD / CNY / tokens without a ×500000 hack or a
missing-exchange-rate bug. Contract of record (server applies it):
  USD    : raw / quota_per_unit
  CNY    : raw / quota_per_unit * usd_exchange_rate
  tokens : raw (no division)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-08 15:36:55 +08:00
co-authored by Claude Opus 4.8
parent 9027f461c4
commit ce733defcb
+37 -10
View File
@@ -11,10 +11,8 @@ import (
"github.com/heicode/manager/setting/operation_setting"
)
// quotaDisplayUnitLabel names the unit the raw quota is denominated in, so the
// desktop client converts exactly like the web dashboard:
// usd = quota / quota_per_unit (mirrors web renderQuotaCompat)
// Returns USD / CNY / tokens.
// quotaDisplayUnitLabel names the unit the raw quota is denominated in.
// Returns USD / CNY / tokens (mirrors the web dashboard's quota display type).
func quotaDisplayUnitLabel() string {
switch operation_setting.GetQuotaDisplayType() {
case operation_setting.QuotaDisplayTypeCNY:
@@ -26,6 +24,24 @@ func quotaDisplayUnitLabel() string {
}
}
// displayQuota converts a raw quota counter to the value the user should SEE,
// for the current站点 display type — server-side so the client never has to
// special-case a mode. This is the contract of record (no hardcoded ×500000):
//
// USD : raw / quota_per_unit
// CNY : raw / quota_per_unit * usd_exchange_rate
// CUSTOM : raw / quota_per_unit * custom_currency_exchange_rate
// tokens : raw (no division)
//
// usd_exchange_rate is the USD→display-currency multiplier returned alongside,
// so clients that prefer raw can recompute the same value.
func displayQuota(raw int, label string, perUnit, rate float64) float64 {
if label == "tokens" || perUnit <= 0 {
return float64(raw)
}
return float64(raw) / perUnit * rate
}
// GetHeicodeSelf serves GET /api/heicode/self.
//
// Mounted on TokenAuth so the cc-haha desktop client can read it with
@@ -59,18 +75,29 @@ func GetHeicodeSelf(c *gin.Context) {
return
}
// Conversion params + server-computed display values so every quota_display_type
// (USD / CNY / tokens / custom) renders correctly without a client-side hack.
label := quotaDisplayUnitLabel()
perUnit := float64(common.QuotaPerUnit)
rate := operation_setting.GetUsdToCurrencyRate(operation_setting.USDExchangeRate) // USD→1, CNY→7.3, tokens→1
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{
"id": user.Id,
"username": user.Username,
"display_name": user.DisplayName,
"group": user.Group,
"role": user.Role,
"id": user.Id,
"username": user.Username,
"display_name": user.DisplayName,
"group": user.Group,
"role": user.Role,
// raw counters (NewAPI internal units) + the params to convert them.
"quota": user.Quota,
"used_quota": user.UsedQuota,
"quota_per_unit": common.QuotaPerUnit,
"quota_display_type": quotaDisplayUnitLabel(),
"quota_display_type": label, // USD / CNY / tokens
"usd_exchange_rate": rate, // USD→display-currency multiplier (1 for USD/tokens)
// ready-to-show values (server applies the display-type formula above).
"display_quota": displayQuota(user.Quota, label, perUnit, rate),
"display_used_quota": displayQuota(user.UsedQuota, label, perUnit, rate),
"request_count": user.RequestCount,
},
})