From 1fd8a14fae44579202fc53fc231ca456284d3009 Mon Sep 17 00:00:00 2001 From: ikmkj Date: Tue, 5 May 2026 16:21:58 +0800 Subject: [PATCH] Restore consistent RMB display and stable image-studio option state after save Constraint: Fix the visible regressions without changing the broader pricing model or image-studio backend contract. Rejected: Ad hoc page-specific symbol patches | would leave model-pricing views inconsistent and fragile. Confidence: high Scope-risk: narrow Directive: Keep model-pricing summaries on shared currency formatting and keep dynamic image-studio model controls fully controlled after save. Tested: cd web && NODE_OPTIONS='--max-old-space-size=4096' npm run build Not-tested: Browser-click verification on the live model plaza and image-studio settings form. --- .../modal/components/ModelPricingTable.jsx | 8 +++- web/src/helpers/utils.jsx | 46 ++++++++++++++++++- .../Setting/Drawing/SettingsImageStudio.jsx | 34 ++++++++------ 3 files changed, 71 insertions(+), 17 deletions(-) diff --git a/web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx b/web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx index b206460..62b03b4 100644 --- a/web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx +++ b/web/src/components/table/model-pricing/modal/components/ModelPricingTable.jsx @@ -20,7 +20,11 @@ For commercial licensing, please contact support@quantumnous.com import React from 'react'; import { Card, Avatar, Typography, Table, Tag } from '@douyinfe/semi-ui'; import { IconCoinMoneyStroked } from '@douyinfe/semi-icons'; -import { calculateModelPrice, getModelPriceItems } from '../../../../../helpers'; +import { + calculateModelPrice, + formatPriceItemValue, + getModelPriceItems, +} from '../../../../../helpers'; const { Text } = Typography; @@ -131,7 +135,7 @@ const ModelPricingTable = ({ {items.map((item) => (
- {item.label} {item.value} + {item.label} {formatPriceItemValue(item, siteDisplayType)}
{item.suffix}
diff --git a/web/src/helpers/utils.jsx b/web/src/helpers/utils.jsx index 77ab7b1..b3997d7 100644 --- a/web/src/helpers/utils.jsx +++ b/web/src/helpers/utils.jsx @@ -880,7 +880,7 @@ export const formatPriceInfo = (priceData, t, quotaDisplayType = 'USD') => { <> {items.map((item) => ( - {item.label} {item.value} + {item.label} {formatPriceItemValue(item, quotaDisplayType)} {item.suffix} ))} @@ -888,6 +888,50 @@ export const formatPriceInfo = (priceData, t, quotaDisplayType = 'USD') => { ); }; +export const formatPriceItemValue = (item, quotaDisplayType = 'USD') => { + if (!item) { + return '-'; + } + + const rawValue = item.value; + if (rawValue === null || rawValue === undefined || rawValue === '') { + return '-'; + } + + if (quotaDisplayType === 'TOKENS' || String(item.suffix || '').includes('x')) { + return rawValue; + } + + const statusStr = localStorage.getItem('status'); + let symbol = '¥'; + let rate = 1; + + if (quotaDisplayType === 'CNY' || quotaDisplayType === 'USD') { + symbol = '¥'; + try { + if (statusStr) { + const status = JSON.parse(statusStr); + rate = status?.usd_exchange_rate || 7; + } + } catch {} + } else if (quotaDisplayType === 'CUSTOM') { + try { + if (statusStr) { + const status = JSON.parse(statusStr); + symbol = status?.custom_currency_symbol || '¤'; + rate = status?.custom_currency_exchange_rate || 1; + } + } catch {} + } + + const numericValue = Number(rawValue); + if (!Number.isFinite(numericValue)) { + return `${symbol}${rawValue}`; + } + + return `${symbol}${Number((numericValue * rate).toFixed(6))}`; +}; + // ------------------------------- // CardPro 分页配置函数 // 用于创建 CardPro 的 paginationArea 配置 diff --git a/web/src/pages/Setting/Drawing/SettingsImageStudio.jsx b/web/src/pages/Setting/Drawing/SettingsImageStudio.jsx index bb5a55e..4da7431 100644 --- a/web/src/pages/Setting/Drawing/SettingsImageStudio.jsx +++ b/web/src/pages/Setting/Drawing/SettingsImageStudio.jsx @@ -35,6 +35,8 @@ const SIZE_OPTIONS = [ ]; const QUALITY_OPTIONS = ['auto', 'low', 'medium', 'high']; +const ALL_SIZE_OPTIONS = [...SIZE_OPTIONS]; +const ALL_QUALITY_OPTIONS = [...QUALITY_OPTIONS]; const normalizeSettings = (value) => { const next = { ...DEFAULT_SETTINGS, ...(value || {}) }; @@ -52,10 +54,10 @@ const normalizeSettings = (value) => { allow_quality: item?.allow_quality !== false, allowed_sizes: Array.isArray(item?.allowed_sizes) ? item.allowed_sizes.filter(Boolean) - : ['auto'], + : ALL_SIZE_OPTIONS, allowed_qualities: Array.isArray(item?.allowed_qualities) ? item.allowed_qualities.filter(Boolean) - : ['auto', 'low', 'medium', 'high'], + : ALL_QUALITY_OPTIONS, default_size: item?.default_size || 'auto', default_quality: item?.default_quality || 'auto', })) @@ -102,6 +104,10 @@ export default function SettingsImageStudio({ options, refresh }) { key: 'ImageStudioRetentionMinutes', value: String(inputs.retention_minutes || 30), }); + const snapshot = structuredClone(inputs); + setInputs(snapshot); + setInputsRow(snapshot); + refForm.current?.setValues(snapshot); showSuccess(t('保存成功')); refresh(); } catch (error) { @@ -224,8 +230,8 @@ export default function SettingsImageStudio({ options, refresh }) { allow_ratio: true, allow_resolution: true, allow_quality: true, - allowed_sizes: ['auto'], - allowed_qualities: ['auto', 'low', 'medium', 'high'], + allowed_sizes: ALL_SIZE_OPTIONS, + allowed_qualities: ALL_QUALITY_OPTIONS, default_size: 'auto', default_quality: 'auto', }; @@ -248,7 +254,7 @@ export default function SettingsImageStudio({ options, refresh }) { label={t('启用该模型')} checkedText='|' uncheckedText='〇' - initValue={setting.enabled} + checked={setting.enabled} onChange={(value) => updateModelSetting(modelName, { enabled: value })} /> @@ -258,7 +264,7 @@ export default function SettingsImageStudio({ options, refresh }) { label={t('允许生成')} checkedText='|' uncheckedText='〇' - initValue={setting.allow_generate} + checked={setting.allow_generate} onChange={(value) => updateModelSetting(modelName, { allow_generate: value }) } @@ -270,7 +276,7 @@ export default function SettingsImageStudio({ options, refresh }) { label={t('允许编辑')} checkedText='|' uncheckedText='〇' - initValue={setting.allow_edit} + checked={setting.allow_edit} onChange={(value) => updateModelSetting(modelName, { allow_edit: value })} /> @@ -280,7 +286,7 @@ export default function SettingsImageStudio({ options, refresh }) { label={t('允许选择质量')} checkedText='|' uncheckedText='〇' - initValue={setting.allow_quality} + checked={setting.allow_quality} onChange={(value) => updateModelSetting(modelName, { allow_quality: value }) } @@ -294,7 +300,7 @@ export default function SettingsImageStudio({ options, refresh }) { label={t('允许切换比例')} checkedText='|' uncheckedText='〇' - initValue={setting.allow_ratio} + checked={setting.allow_ratio} onChange={(value) => updateModelSetting(modelName, { allow_ratio: value }) } @@ -306,7 +312,7 @@ export default function SettingsImageStudio({ options, refresh }) { label={t('允许切换分辨率')} checkedText='|' uncheckedText='〇' - initValue={setting.allow_resolution} + checked={setting.allow_resolution} onChange={(value) => updateModelSetting(modelName, { allow_resolution: value }) } @@ -320,7 +326,7 @@ export default function SettingsImageStudio({ options, refresh }) { label={t('允许分辨率')} multiple optionList={SIZE_OPTIONS.map((item) => ({ label: item, value: item }))} - initValue={setting.allowed_sizes} + value={setting.allowed_sizes} onChange={(value) => updateModelSetting(modelName, { allowed_sizes: Array.isArray(value) ? value : [], @@ -334,7 +340,7 @@ export default function SettingsImageStudio({ options, refresh }) { label={t('允许质量')} multiple optionList={QUALITY_OPTIONS.map((item) => ({ label: item, value: item }))} - initValue={setting.allowed_qualities} + value={setting.allowed_qualities} onChange={(value) => updateModelSetting(modelName, { allowed_qualities: Array.isArray(value) ? value : [], @@ -349,7 +355,7 @@ export default function SettingsImageStudio({ options, refresh }) { field={`model_settings_${modelName}_default_size`} label={t('默认分辨率')} optionList={SIZE_OPTIONS.map((item) => ({ label: item, value: item }))} - initValue={setting.default_size} + value={setting.default_size} onChange={(value) => updateModelSetting(modelName, { default_size: String(value || 'auto') }) } @@ -360,7 +366,7 @@ export default function SettingsImageStudio({ options, refresh }) { field={`model_settings_${modelName}_default_quality`} label={t('默认质量')} optionList={QUALITY_OPTIONS.map((item) => ({ label: item, value: item }))} - initValue={setting.default_quality} + value={setting.default_quality} onChange={(value) => updateModelSetting(modelName, { default_quality: String(value || 'auto'),