fix: 修复兑换码额度精度损失 (#6685)

* fix: 修复兑换码额度精度损失(#6680)

* fix(redemption): guard update data integrity
This commit is contained in:
lihu-001
2026-08-07 17:06:32 +08:00
committed by GitHub
parent 1da23d6b33
commit e926e5cace
5 changed files with 721 additions and 146 deletions
+23 -3
View File
@@ -244,6 +244,23 @@ function mergeOptions(
}
}
function getFractionDigits(
value: number,
digitsLarge: number,
digitsSmall: number
): number {
return Math.abs(value) >= 1 ? digitsLarge : digitsSmall
}
/** Return the configured fraction digits for a plain currency value. */
export function getCurrencyFractionDigits(
value: number,
options?: CurrencyFormatOptions
): number {
const merged = mergeOptions(options)
return getFractionDigits(value, merged.digitsLarge, merged.digitsSmall)
}
function removeTrailingZeros(str: string): string {
if (!str.includes('.')) return str
return str.replace(/(\.[0-9]*?)0+$/, '$1').replace(/\.$/, '')
@@ -261,7 +278,7 @@ function formatNumberWithSuffix(
return `${removeTrailingZeros(result.toFixed(1))}k`
}
const digits = abs >= 1 ? digitsLarge : digitsSmall
const digits = getFractionDigits(value, digitsLarge, digitsSmall)
return removeTrailingZeros(value.toFixed(digits))
}
@@ -300,8 +317,11 @@ function formatCurrencyValue(
)
}
const digits =
Math.abs(value) >= 1 ? options.digitsLarge : options.digitsSmall
const digits = getFractionDigits(
value,
options.digitsLarge,
options.digitsSmall
)
const adjustedValue = adjustForMinimum(value, digits, options.minimumNonZero)
if (meta.kind === 'currency') {
+33 -4
View File
@@ -22,6 +22,7 @@ import {
formatCurrencyFromUSD,
formatQuotaWithCurrency,
getCurrencyDisplay,
getCurrencyFractionDigits,
} from './currency'
// ============================================================================
@@ -104,16 +105,44 @@ export function parseQuotaFromDollars(amount: number): number {
*/
export function quotaUnitsToDollars(units: number): number {
const { config, meta } = getCurrencyDisplay()
return quotaUnitsToDisplayAmount(units, config.quotaPerUnit, meta)
}
function quotaUnitsToDisplayAmount(
units: number,
quotaPerUnit: number,
meta: ReturnType<typeof getCurrencyDisplay>['meta']
): number {
if (meta.kind === 'tokens') {
return units
}
const usdAmount = units / config.quotaPerUnit
const exchangeRate =
meta.kind === 'currency' || meta.kind === 'custom' ? meta.exchangeRate : 1
return (units / quotaPerUnit) * meta.exchangeRate
}
return usdAmount * exchangeRate
/**
* Convert quota units to a plain number suitable for an editable input.
* Uses the same precision as quota list formatting without symbols or suffixes.
*/
export function quotaUnitsToEditableAmount(units: number): number {
const { config, meta } = getCurrencyDisplay()
const amount = quotaUnitsToDisplayAmount(units, config.quotaPerUnit, meta)
if (meta.kind === 'tokens') {
return Math.round(amount)
}
return Number(amount.toFixed(getCurrencyFractionDigits(amount)))
}
/** Return the input step matching the configured editable quota precision. */
export function getEditableQuotaStep(): number {
const { meta } = getCurrencyDisplay()
if (meta.kind === 'tokens') {
return 1
}
return 10 ** -getCurrencyFractionDigits(0)
}
// ============================================================================