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 ? (