1. 22 Apr, 2026 4 commits
  2. 21 Apr, 2026 10 commits
  3. 20 Apr, 2026 6 commits
    • IanShaw027's avatar
      c297d011
    • IanShaw027's avatar
      Close profile identity and avatar loop · 92041457
      IanShaw027 authored
      92041457
    • IanShaw027's avatar
      Refine payment UX for wallet flows · f83fd59d
      IanShaw027 authored
      f83fd59d
    • erio's avatar
      feat(payment): i18n payment error codes and label localization · 40d4e167
      erio authored
      Pairs with the backend structured payment errors (reason + metadata). The
      frontend now maps reason codes to localized messages with metadata as
      interpolation variables, and automatically localizes raw config-field names
      (e.g. "certSerial" → "证书序列号") using the existing UI-label i18n
      namespace.
      
      - frontend/src/utils/apiError.ts
        - extractApiErrorCode now prefers the string `reason` over the numeric HTTP
          `code`; reason is granular enough to drive i18n lookup, HTTP code is not.
        - New extractApiErrorMetadata to pull interpolation params off the error.
        - New extractI18nErrorMessage(err, t, namespace, fallback): looks up
          `<namespace>.<REASON>` in i18n and substitutes metadata. Before
          substitution, `metadata.key` and `metadata.keys` (slash-joined) are
          re-translated through `admin.settings.payment.field_<key>` so users see
          "缺少必填项:证书序列号" instead of "缺少必填项:certSerial".
      
      - frontend/src/i18n/locales/{zh,en}.ts
        - Add payment.errors entries for every structured reason code returned by
          the backend (PAYMENT_DISABLED, INVALID_AMOUNT, TOO_MANY_PENDING,
          DAILY_LIMIT_EXCEEDED, NO_AVAILABLE_INSTANCE, PAYMENT_PROVIDER_MISCONFIGURED,
          WXPAY_CONFIG_MISSING_KEY / INVALID_KEY_LENGTH / INVALID_KEY, NOT_FOUND,
          FORBIDDEN, CONFLICT, INVALID_ORDER_TYPE, INVALID_STATUS,
          BALANCE_NOT_ENOUGH, REFUND_AMOUNT_EXCEEDED, REFUND_FAILED, and more),
          with placeholders for template variables.
      
      - 13 payment-related Vue files
        - Migrate catch-block error reporting from extractApiErrorMessage to
          extractI18nErrorMessage(err, t, 'payment.errors', fallback).
        - Remove the ad-hoc paymentErrorMap computed in SettingsView.vue, which the
          new helper supersedes (it reads i18n directly via t).
      
      - frontend/src/components/payment/providerConfig.ts
        - wxpay: publicKey and publicKeyId are now required (was optional), matching
          the pubkey-only verifier direction; certSerial is already required.
      
      This PR is drop-in safe: reason-preferring extractApiErrorCode is backward
      compatible with callers that pass their own i18nMap, and error codes missing
      from i18n fall back to the existing message-based path.
      40d4e167
    • IanShaw027's avatar
      feat: add profile auth identity binding flow · c6d85924
      IanShaw027 authored
      c6d85924
    • IanShaw027's avatar
      13d9780d
  4. 19 Apr, 2026 1 commit
  5. 15 Apr, 2026 1 commit
    • erio's avatar
      feat(usage): add account cost display to admin dashboard and usage pages · 6ade6d30
      erio authored
      - Add account_cost column to dashboard aggregation tables (migration 107)
      - DashboardStats: add TotalAccountCost/TodayAccountCost fields
      - ModelStat/GroupStat: add AccountCost field with SQL aggregation
      - GetStatsWithFilters: always return TotalAccountCost (remove accountID filter)
      - Dashboard Token cards: show user(green)/cost(orange)/standard(gray)
      - Usage stats card: show account cost and standard below main value
      - Model/Group distribution tables: add orange cost column
      6ade6d30
  6. 14 Apr, 2026 18 commits
    • erio's avatar
      fix(payment): integrate recharge fee rate in order flow and fix UI display · e761d38f
      erio authored
      Backend:
      - Use cfg.RechargeFeeRate in order creation instead of hardcoded 0
      - Remove dead getFeeRate stub method
      - All amounts computed server-side: order_amount, pay_amount, fee_rate
      
      Frontend - PaymentView:
      - Read recharge_fee_rate from checkout-info API (not per-method)
      - Show fee breakdown only when fee_rate > 0
      - Show credited amount only when multiplier ≠ 1
      
      Frontend - Order display (user + admin):
      - Fix fee_rate * 100 bug (fee_rate is already a percentage)
      - OrderTable: show pay_amount as primary, fee/credited as sub-lines
      - AdminOrderDetail: full breakdown (base/fee/paid/credited)
      - AdminRefundDialog: label "到账金额" for clarity
      - PaymentResultView: show pay_amount with fee info
      
      Types + i18n:
      - Add recharge_fee_rate to CheckoutInfoResponse
      - Add fee_rate to CreateOrderResult
      - Add translations: creditedAmount, fee, baseAmount, includedInPayAmount
      e761d38f
    • erio's avatar
      feat(payment): add recharge fee rate setting and fix provider card UI · 98140f6c
      erio authored
      - Add recharge_fee_rate system setting (percentage fee on top of recharge amount)
      - Full backend chain: config constant, PaymentConfig struct, update validation,
        read/write persistence, DTO, handler GET/PUT responses
      - Frontend: settings input with preview, i18n (zh/en), API types
      - Fix provider card toggle layout: labels above switches to save width
      - Fix Chinese translation: "EasyPay" → "易支付" in provider description
      98140f6c
    • erio's avatar
      feat(payment): balance recharge multiplier and refund amount separation · 60a4b931
      erio authored
      - Add balance_recharge_multiplier system setting (e.g. 1.2 = charge 100 get 120)
      - Separate order_amount (credited balance) from pay_amount (actual payment)
      - Refund calculates gateway amount proportionally from pay_amount
      - Frontend shows both amounts in order details, payment status, refund dialog
      - Admin settings UI for configuring recharge multiplier
      60a4b931
    • erio's avatar
      fix: merge general improvements from release branch · 63f539b3
      erio authored
      Backend:
      - gateway_handler: pass subject.UserID instead of int64(0) for user-level routing
      - setting_handler: add missing BalanceLowNotifyRechargeURL to UpdateSettings response
      - openai_gateway_service: use applyAccountStatsCost for account stats pricing integration
      - embed_on: add local file override (data/public/) for embedded frontend assets
      
      Frontend:
      - useTableSelection: add batchUpdate method for batch operations
      - AccountsView: virtual scrolling params, Set-based isSelected, swipe virtualization
      - ProxiesView: add batchUpdate to selection and swipe-select
      - BulkEditAccountModal: fix submit handler to prevent event object as argument
      - SettingsView: move payload construction outside try block
      - i18n: add general translation keys (saved, deleted, view, validation, allowUserRefund)
      - api/client: reorder error fields for consistency
      - stores/payment: clarify pollOrderStatus JSDoc
      63f539b3
    • erio's avatar
      feat: add per-provider allow_user_refund control and align wildcard matching · f1297a36
      erio authored
      allow_user_refund:
      - Add allow_user_refund field to PaymentProviderInstance ent schema
      - Migration 103: ALTER TABLE payment_provider_instances ADD COLUMN
      - Cascade logic: disabling refund_enabled auto-disables allow_user_refund
      - User refund validation: check provider instance allows user refund
      - Admin refund validation: check provider instance allows admin refund
      - Subscription refund: deduct days on refund, rollback on failure
      - New endpoint: GET /payment/orders/refund-eligible-providers
      - Frontend: ToggleSwitch in ProviderCard/Dialog, cascade in SettingsView
      
      Wildcard matching:
      - Change findPricingForModel from "longest prefix wins" to "config order
        priority (first match wins)", aligning with channel service behavior
      f1297a36
    • erio's avatar
      feat: websearch quota enhancements and balance notify hint · 7c729293
      erio authored
      - QuotaLimit changed to *int64 (null=unlimited, >0=limited)
      - Add reset-usage endpoint (POST /admin/settings/web-search-emulation/reset-usage)
      - Show quota usage in header always (collapsed and expanded)
      - Add reset quota button in expanded provider view
      - Quota input: empty=unlimited with ∞ placeholder, must be >0 if set
      - Add email verification hint on balance notify card
      7c729293
    • erio's avatar
      feat(notify): add platform/ID to quota alert email, add recharge URL to balance alert · c1eb79e4
      erio authored
      - Quota alert email now shows account ID and platform
      - Balance low email includes a "Top Up Now" button when recharge URL is configured
      - New setting: balance_low_notify_recharge_url in admin settings
      c1eb79e4
    • erio's avatar
      fix: change quota notify threshold semantics to "remaining quota" · 216bda58
      erio authored
      Threshold now represents remaining quota instead of usage amount:
      - Fixed ($): threshold=400, limit=1000 → alert when remaining drops to $400
        (i.e., usage reaches $600)
      - Percentage (%): threshold=30%, limit=1000 → alert when remaining drops
        to 30% (i.e., usage reaches $700)
      
      Also:
      - Rename 告警阈值 → 提醒阈值 in i18n
      - Widen type dropdown to w-16 for proper $ / % display
      216bda58
    • erio's avatar
      fix(frontend): simplify websearch select labels and reduce width · 245f47ce
      erio authored
      - "默认(跟随渠道)" → "默认", "Default (follow channel)" → "Default"
      - Move "follows channel config" info to description text
      - Reduce select width from w-32 to w-24 in both Edit and Create modals
      245f47ce
    • erio's avatar
      fix: address audit findings across websearch, notify, and channel pricing · a68df457
      erio authored
      Backend fixes:
      - Fix balance notify ignoring percentage threshold type (was treating
        percentage value as fixed USD amount)
      - Remove dead code parseJSONStringArray
      - Add ImageOutputTokens to tryModelFilePricing calculation
      - Unify zero-value check: cost == 0 → cost <= 0 in calculateTokenStatsCost
      - Use MarshalNotifyEmails instead of json.Marshal for consistency
      - Rename quotaDim.oldUsed → currentUsed for clarity
      - Extract HTML email templates to const variables (function ≤30 lines)
      
      Test fixes:
      - Rewrite account_websearch_test.go for GetWebSearchEmulationMode tri-state
      - Add 6 tryModelFilePricing test cases
      
      Frontend fixes:
      - Replace hardcoded '未命名' with i18n key
      - Extract getBillingModeLabel/getBillingModeBadgeClass to shared utils
      - Replace inline type with imported NotifyEmailEntry
      - Pass platform to AccountStats pricing rules via inferRulePlatform()
      - Add billing mode constants (BILLING_MODE_TOKEN/PER_REQUEST/IMAGE)
      a68df457
    • erio's avatar
      feat: WebSearch tri-state, account stats pricing fix, quota cache fix, usage tooltip · 1262654d
      erio authored
      WebSearch tri-state switch:
      - Account-level web_search_emulation changed from bool to tri-state
        string: "default" (follow channel) / "enabled" / "disabled"
      - shouldEmulateWebSearch checks channel config when account is "default"
      - SQL migration converts old bool values
      - Frontend select replaces toggle in Edit/CreateAccountModal
      
      Account stats pricing:
      - resolveAccountStatsCost uses upstream model (post-mapping) for matching
      - Priority: custom rules → model pricing file (when toggle on) → default
      - Custom rules always configurable, independent of toggle
      - Account ID field changed to searchable selector filtered by platform
      - Description updated to reflect new behavior
      
      Quota notification cache fix:
      - CheckAccountQuotaAfterIncrement fetches real-time account from DB
      - Reconstructs pre-increment usage for accurate threshold crossing detection
      - New AccountQuotaReader interface (minimal: GetByID only)
      
      Usage tooltip:
      - Per-request/image billing shows per-request price instead of $0 token price
      - Token billing continues to show input/output price per million tokens
      1262654d
    • erio's avatar
      fix(channel): use upstream model for account stats pricing and remove channel pricing fallback · 11c46068
      erio authored
      - resolveAccountStatsCost now uses the final upstream model (after
        account-level mapping) to match custom pricing rules, fixing the
        issue where requested model (e.g. claude-sonnet-4-5) didn't match
        rules configured for upstream model (e.g. claude-opus-4-6)
      - Remove tryChannelPricing fallback — only custom rules are applied,
        unmatched requests use default formula (total_cost × rate)
      - Remove unused billingService and serviceTier parameters
      - Update description: "启用后将支持自定义账号统计的模型价格"
      11c46068
    • erio's avatar
      fix(notify): use real-time balance for crossing detection and simplify email logic · 31550a2c
      erio authored
      - Fix cached balance causing threshold crossing to never trigger:
        read real-time balance from billingCacheService instead of stale
        API key auth snapshot
      - Remove email="" placeholder concept; all emails are user-managed
      - Only send notifications to verified && non-disabled emails
      - Frontend: pre-fill user's email in add input when list is empty
      - Remove FilterEnabledEmails/IsPrimaryDisabled helpers (no longer needed)
      31550a2c
    • erio's avatar
      feat(notify): convert email lists to NotifyEmailEntry struct with toggle support · 915b7a4a
      erio authored
      - Change balance_notify_extra_emails and account_quota_notify_emails
        from []string to []NotifyEmailEntry{email, disabled, verified}
      - Add per-email enable/disable toggle for both user and admin notifications
      - Add PUT /user/notify-email/toggle API endpoint
      - Fix critical bug: API key auth cache snapshot missing balance notify
        fields (Email, Username, BalanceNotifyEnabled, etc.), causing
        notifications to never fire on cached request paths
      - Bump cache snapshot version 3→4 to invalidate stale entries
      - Add SQL migration 104 to convert old format data
      - Backward compatible: parseNotifyEmails auto-detects old/new format
      - User balance notify: max 3 emails (primary + 2 extra)
      - Admin quota notify: unlimited emails, each with toggle
      915b7a4a
    • erio's avatar
    • erio's avatar
      feat(notify): improve balance notify card UX · 81287e96
      erio authored
      - Show system default threshold as placeholder in custom threshold input
      - Display user's primary email with "Primary" badge
      - Support adding multiple pending emails before verification
      - Each pending email has independent send/verify/resend flow
      - Expose balance_low_notify_threshold in PublicSettings API
      - Clean up timers on unmount to prevent leaks
      81287e96
    • erio's avatar
      feat(notify): add global toggles, percentage threshold, and visibility control · eba289a7
      erio authored
      - Add global toggle for account quota notification in admin settings
      - Add percentage-based threshold type for per-account quota alerts
      - Hide balance notify card on user profile when global toggle is off
      - Expose balance_low_notify_enabled and account_quota_notify_enabled in PublicSettings
      - Add threshold type (fixed/percentage) to QuotaNotifyToggle with $ / % switcher
      eba289a7
    • erio's avatar
      fix(notify): remove percentage threshold from balance notification · cef22c70
      erio authored
      Balance low notification only supports fixed USD amount threshold.
      Percentage threshold is a quota concept, not applicable to balance.
      Reverted threshold_type from admin settings, user profile, and all
      backend/frontend layers. DB fields (balance_notify_threshold_type,
      total_recharged) retained for potential future quota use.
      cef22c70