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.
This commit is contained in:
ikmkj
2026-05-05 16:21:58 +08:00
parent ca368972b3
commit 1fd8a14fae
3 changed files with 71 additions and 17 deletions

View File

@@ -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) => (
<div key={item.key}>
<div className='font-semibold text-orange-600'>
{item.label} {item.value}
{item.label} {formatPriceItemValue(item, siteDisplayType)}
</div>
<div className='text-xs text-gray-500'>{item.suffix}</div>
</div>

View File

@@ -880,7 +880,7 @@ export const formatPriceInfo = (priceData, t, quotaDisplayType = 'USD') => {
<>
{items.map((item) => (
<span key={item.key} style={{ color: 'var(--semi-color-text-1)' }}>
{item.label} {item.value}
{item.label} {formatPriceItemValue(item, quotaDisplayType)}
{item.suffix}
</span>
))}
@@ -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 配置

View File

@@ -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 })}
/>
</Col>
@@ -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 })}
/>
</Col>
@@ -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'),