diff --git a/web/src/components/settings/RatioSetting.jsx b/web/src/components/settings/RatioSetting.jsx
index 1b7b67f..f2776e8 100644
--- a/web/src/components/settings/RatioSetting.jsx
+++ b/web/src/components/settings/RatioSetting.jsx
@@ -27,6 +27,7 @@ import ModelSettingsVisualEditor from '../../pages/Setting/Ratio/ModelSettingsVi
import ModelRatioNotSetEditor from '../../pages/Setting/Ratio/ModelRationNotSetEditor';
import UpstreamRatioSync from '../../pages/Setting/Ratio/UpstreamRatioSync';
import PricingTagManager from '../../pages/Setting/Ratio/PricingTagManager';
+import ModelPricing from '../../pages/Setting/Operation/ModelPricing';
import { API, showError, toBoolean } from '../../helpers';
@@ -111,6 +112,11 @@ const RatioSetting = () => {
+
+
+
+
+
diff --git a/web/src/pages/Setting/Operation/ModelPricing/DimensionEditor.jsx b/web/src/pages/Setting/Operation/ModelPricing/DimensionEditor.jsx
index 9e863a5..5d461a9 100644
--- a/web/src/pages/Setting/Operation/ModelPricing/DimensionEditor.jsx
+++ b/web/src/pages/Setting/Operation/ModelPricing/DimensionEditor.jsx
@@ -1,10 +1,8 @@
import React from 'react';
-import { Button, Checkbox, Input, Select, Space, Table } from '@douyinfe/semi-ui';
-import { Plus, Trash2 } from 'lucide-react';
+import { Button, Checkbox, Input, Select, Space, Table, Tooltip, Typography } from '@douyinfe/semi-ui';
+import { Info, Plus, Trash2 } from 'lucide-react';
import { useTranslation } from 'react-i18next';
-import { parseDimensionValue } from './pricingConfig';
-
-const SOURCE_OPTIONS = ['request.resolution', 'request.duration', 'request.options.size', 'derived.input_mode', 'derived.megapixels', 'derived.aspect_ratio'];
+import { DIMENSION_SOURCE_TYPES, composeDimensionSource, parseDimensionValue, splitDimensionSource } from './pricingConfig';
export default function DimensionEditor({ dimensions, onChange }) {
const { t } = useTranslation();
@@ -19,13 +17,66 @@ export default function DimensionEditor({ dimensions, onChange }) {
const add = () => onChange([...dimensions, { key: 'duration', source: 'request.duration', type: 'number', default: null }]);
const columns = [
- { title: t('Key'), dataIndex: 'key', render: (value, _, index) => update(index, { key })} /> },
+ { title: t('Key'), dataIndex: 'key', width: 140, render: (value, _, index) => update(index, { key })} data-testid={`dimension-key-${index}`} /> },
+ {
+ title: (
+
+ {t('来源类型')}
+
+
+
+
+ ),
+ dataIndex: 'source_type',
+ width: 140,
+ render: (_, row, index) => {
+ const parsed = splitDimensionSource(row.source);
+ return (
+
+ );
+ },
+ },
+ {
+ title: t('路径'),
+ dataIndex: 'source_path',
+ width: 210,
+ render: (_, row, index) => {
+ const parsed = splitDimensionSource(row.source);
+ return (
+ update(index, { source: composeDimensionSource(parsed.sourceType, path) })}
+ data-testid={`dimension-source-path-${index}`}
+ />
+ );
+ },
+ },
{
- title: t('来源'),
+ title: t('保存值'),
dataIndex: 'source',
- render: (value, _, index) => (
-