fix: round-2 audit fixes — security, code quality, and UI improvements
Security (HIGH): - Normalize all Redis cache keys to lowercase (verifyCode, passwordReset) - Fix verify code TTL renewal on failed attempts: use remaining TTL via ExpiresAt field instead of resetting to full 15-minute window - Add 3 missing fields to diffSettings audit log (promo_code, invitation_code, custom_endpoints) Code quality (MEDIUM): - Extract filterVerifiedEmails shared helper (balance_notify_service.go) - Add Pricing array non-empty validation for channel pricing rules - Add platform token semantics comment in gateway_service.go - Complete validatePlanPatch test coverage (+10 test cases) - Replace string types with QuotaThresholdType/QuotaResetMode across frontend - Remove duplicate getPlatformTextColor/getRateBadgeClass in ChannelsView - Return EMAIL_NOT_FOUND error on RemoveNotifyEmail miss UI improvements: - Reorder cost tooltip: user billing above separator, account billing below - Add NaN guard to accountBilled function - Move timezone selector inline into reset-mode row (no longer standalone)
This commit is contained in:
@@ -313,10 +313,6 @@
|
||||
<span class="text-gray-400">{{ t('usage.rate') }}</span>
|
||||
<span class="font-semibold text-blue-400">{{ formatMultiplier(tooltipData?.rate_multiplier || 1) }}x</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-6">
|
||||
<span class="text-gray-400">{{ t('usage.accountMultiplier') }}</span>
|
||||
<span class="font-semibold text-blue-400">{{ formatMultiplier(tooltipData?.account_rate_multiplier ?? 1) }}x</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-6">
|
||||
<span class="text-gray-400">{{ t('usage.original') }}</span>
|
||||
<span class="font-medium text-white">${{ tooltipData?.total_cost?.toFixed(6) || '0.000000' }}</span>
|
||||
@@ -325,7 +321,12 @@
|
||||
<span class="text-gray-400">{{ t('usage.userBilled') }}</span>
|
||||
<span class="font-semibold text-green-400">${{ tooltipData?.actual_cost?.toFixed(6) || '0.000000' }}</span>
|
||||
</div>
|
||||
<!-- Account billing (separated from user billing) -->
|
||||
<div class="flex items-center justify-between gap-6 border-t border-gray-700 pt-1.5">
|
||||
<span class="text-gray-400">{{ t('usage.accountMultiplier') }}</span>
|
||||
<span class="font-semibold text-blue-400">{{ formatMultiplier(tooltipData?.account_rate_multiplier ?? 1) }}x</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-6">
|
||||
<span class="text-gray-400">{{ t('usage.accountBilled') }}</span>
|
||||
<span class="font-semibold text-green-400">
|
||||
${{ accountBilled({
|
||||
@@ -355,7 +356,8 @@ import { getBillingModeLabel, getBillingModeBadgeClass, BILLING_MODE_TOKEN, BILL
|
||||
/** Compute the account-billed cost for display: (account_stats_cost ?? total_cost) * rate_multiplier */
|
||||
function accountBilled(row: { total_cost?: number | null; account_stats_cost?: number | null; account_rate_multiplier?: number | null }): number {
|
||||
const base = row.account_stats_cost != null ? row.account_stats_cost : (row.total_cost ?? 0)
|
||||
return base * (row.account_rate_multiplier ?? 1)
|
||||
const result = base * (row.account_rate_multiplier ?? 1)
|
||||
return Number.isNaN(result) ? 0 : result
|
||||
}
|
||||
|
||||
import DataTable from '@/components/common/DataTable.vue'
|
||||
|
||||
Reference in New Issue
Block a user