diff --git a/web/classic/src/pages/Setting/Ratio/ModelPricingCombined.jsx b/web/classic/src/pages/Setting/Ratio/ModelPricingCombined.jsx index 51dfe27d3a6..c008e942ba2 100644 --- a/web/classic/src/pages/Setting/Ratio/ModelPricingCombined.jsx +++ b/web/classic/src/pages/Setting/Ratio/ModelPricingCombined.jsx @@ -18,7 +18,7 @@ For commercial licensing, please contact support@quantumnous.com */ import React, { useState } from 'react'; -import { Radio, RadioGroup } from '@douyinfe/semi-ui'; +import { Banner, Radio, RadioGroup } from '@douyinfe/semi-ui'; import { useTranslation } from 'react-i18next'; import ModelPricingEditor from './components/ModelPricingEditor'; import ModelRatioSettings from './ModelRatioSettings'; @@ -37,13 +37,25 @@ export default function ModelPricingCombined({ options, refresh }) { onChange={(e) => setEditMode(e.target.value)} > {t('可视化编辑')} - {t('手动编辑')} + {t('倍率(高级)')} {editMode === 'visual' ? ( ) : ( - + <> + + + )} ); diff --git a/web/classic/src/pages/Setting/Ratio/components/ModelPricingEditor.jsx b/web/classic/src/pages/Setting/Ratio/components/ModelPricingEditor.jsx index 2beafe01d93..2e27fa2e748 100644 --- a/web/classic/src/pages/Setting/Ratio/components/ModelPricingEditor.jsx +++ b/web/classic/src/pages/Setting/Ratio/components/ModelPricingEditor.jsx @@ -17,7 +17,7 @@ along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useContext, useMemo, useState } from 'react'; import { Banner, Button, @@ -45,15 +45,20 @@ import { PAGE_SIZE, PRICE_SUFFIX, buildSummaryText, + formatDisplayPrice, hasValue, + normalizeRate, useModelPricingEditorState, } from '../hooks/useModelPricingEditorState'; import { useIsMobile } from '../../../../hooks/common/useIsMobile'; +import { StatusContext } from '../../../../context/Status'; import TieredPricingEditor from './TieredPricingEditor'; const { Text } = Typography; const EMPTY_CANDIDATE_MODEL_NAMES = []; +// 显示固定 2 位(¥4.00),编辑时才展开原始精度串;失焦不回写圆整值, +// 故 model state 始终保持高精度,序列化不受 2 位显示影响(见设计 §6.1.1)。 const PriceInput = ({ label, value, @@ -64,26 +69,40 @@ const PriceInput = ({ extraText = '', headerAction = null, hidden = false, -}) => ( -
-
- {label} - {headerAction} +}) => { + const [focused, setFocused] = useState(false); + const [draft, setDraft] = useState(''); + const displayValue = focused ? draft : formatDisplayPrice(value); + return ( +
+
+ {label} + {headerAction} +
+ {!hidden ? ( + { + // 编辑起点用原始高精度串,避免廉价模型(如 ¥0.0146)被 2 位显示圆整后丢精度。 + setDraft(value ?? ''); + setFocused(true); + }} + onBlur={() => setFocused(false)} + onChange={(v) => { + setDraft(v); + onChange(v); + }} + suffix={suffix} + disabled={disabled} + /> + ) : null} + {extraText ? ( +
{extraText}
+ ) : null}
- {!hidden ? ( - - ) : null} - {extraText ? ( -
{extraText}
- ) : null} -
-); + ); +}; export default function ModelPricingEditor({ options, @@ -99,6 +118,12 @@ export default function ModelPricingEditor({ }) { const { t } = useTranslation(); const isMobile = useIsMobile(); + const [statusState] = useContext(StatusContext); + // 优先用页面级、随保存刷新的 options.USDExchangeRate;StatusContext 仅 app 启动加载一次, + // 改汇率后同会话不刷新会折算错(写错计费倍率),故仅作兜底。 + const rate = normalizeRate( + options?.USDExchangeRate ?? statusState?.status?.usd_exchange_rate, + ); const [addVisible, setAddVisible] = useState(false); const [batchVisible, setBatchVisible] = useState(false); const [newModelName, setNewModelName] = useState(''); @@ -136,6 +161,7 @@ export default function ModelPricingEditor({ t, candidateModelNames, filterMode, + rate, }); const getExprModeLabel = useCallback((model) => { @@ -253,6 +279,17 @@ export default function ModelPricingEditor({ return ( <> + {allowAddModel ? (