🎨 chore(web): apply ESLint and Prettier auto-fixes (baseline)

- Ran: bun run eslint:fix && bun run lint:fix
- Inserted AGPL license header via eslint-plugin-header
- Enforced no-multiple-empty-lines and other lint rules
- Formatted code using Prettier v3 (@so1ve/prettier-config)
- No functional changes; formatting-only baseline across JS/JSX files
This commit is contained in:
t0ng7u
2025-08-30 21:15:10 +08:00
parent 41cf516ec5
commit 0d57b1acd4
274 changed files with 11025 additions and 7659 deletions

View File

@@ -133,9 +133,7 @@ export default function GroupRatioSettings(props) {
message: t('不是合法的 JSON 字符串'),
},
]}
onChange={(value) =>
setInputs({ ...inputs, GroupRatio: value })
}
onChange={(value) => setInputs({ ...inputs, GroupRatio: value })}
/>
</Col>
</Row>
@@ -213,7 +211,7 @@ export default function GroupRatioSettings(props) {
}
// Check if every element is a string
return parsed.every(item => typeof item === 'string');
return parsed.every((item) => typeof item === 'string');
} catch (error) {
return false;
}
@@ -221,9 +219,7 @@ export default function GroupRatioSettings(props) {
message: t('必须是有效的 JSON 字符串数组,例如:["g1","g2"]'),
},
]}
onChange={(value) =>
setInputs({ ...inputs, AutoGroups: value })
}
onChange={(value) => setInputs({ ...inputs, AutoGroups: value })}
/>
</Col>
</Row>

View File

@@ -155,9 +155,7 @@ export default function ModelRatioSettings(props) {
message: '不是合法的 JSON 字符串',
},
]}
onChange={(value) =>
setInputs({ ...inputs, ModelPrice: value })
}
onChange={(value) => setInputs({ ...inputs, ModelPrice: value })}
/>
</Col>
</Row>
@@ -176,9 +174,7 @@ export default function ModelRatioSettings(props) {
message: '不是合法的 JSON 字符串',
},
]}
onChange={(value) =>
setInputs({ ...inputs, ModelRatio: value })
}
onChange={(value) => setInputs({ ...inputs, ModelRatio: value })}
/>
</Col>
</Row>
@@ -197,9 +193,7 @@ export default function ModelRatioSettings(props) {
message: '不是合法的 JSON 字符串',
},
]}
onChange={(value) =>
setInputs({ ...inputs, CacheRatio: value })
}
onChange={(value) => setInputs({ ...inputs, CacheRatio: value })}
/>
</Col>
</Row>

View File

@@ -28,7 +28,7 @@ import {
RadioGroup,
Radio,
Checkbox,
Tag
Tag,
} from '@douyinfe/semi-ui';
import {
IconDelete,
@@ -72,7 +72,8 @@ export default function ModelSettingsVisualEditor(props) {
const modelData = Array.from(modelNames).map((name) => {
const price = modelPrice[name] === undefined ? '' : modelPrice[name];
const ratio = modelRatio[name] === undefined ? '' : modelRatio[name];
const comp = completionRatio[name] === undefined ? '' : completionRatio[name];
const comp =
completionRatio[name] === undefined ? '' : completionRatio[name];
return {
name,
@@ -263,7 +264,8 @@ export default function ModelSettingsVisualEditor(props) {
if (model.name !== name) return model;
const updated = { ...model, [field]: value };
updated.hasConflict =
updated.price !== '' && (updated.ratio !== '' || updated.completionRatio !== '');
updated.price !== '' &&
(updated.ratio !== '' || updated.completionRatio !== '');
return updated;
}),
);
@@ -349,7 +351,8 @@ export default function ModelSettingsVisualEditor(props) {
completionRatio: values.completionRatio || '',
};
updated.hasConflict =
updated.price !== '' && (updated.ratio !== '' || updated.completionRatio !== '');
updated.price !== '' &&
(updated.ratio !== '' || updated.completionRatio !== '');
return updated;
}),
);
@@ -371,7 +374,8 @@ export default function ModelSettingsVisualEditor(props) {
completionRatio: values.completionRatio || '',
};
newModel.hasConflict =
newModel.price !== '' && (newModel.ratio !== '' || newModel.completionRatio !== '');
newModel.price !== '' &&
(newModel.ratio !== '' || newModel.completionRatio !== '');
return [newModel, ...prev];
});
setVisible(false);

View File

@@ -37,13 +37,19 @@ import {
AlertTriangle,
CheckCircle,
} from 'lucide-react';
import { API, showError, showSuccess, showWarning, stringToColor } from '../../../helpers';
import {
API,
showError,
showSuccess,
showWarning,
stringToColor,
} from '../../../helpers';
import { useIsMobile } from '../../../hooks/common/useIsMobile';
import { DEFAULT_ENDPOINT } from '../../../constants';
import { useTranslation } from 'react-i18next';
import {
IllustrationNoResult,
IllustrationNoResultDark
IllustrationNoResultDark,
} from '@douyinfe/semi-illustrations';
import ChannelSelectorModal from '../../../components/settings/ChannelSelectorModal';
@@ -72,7 +78,12 @@ function ConflictConfirmModal({ t, visible, items, onOk, onCancel }) {
onOk={onOk}
size={isMobile ? 'full-width' : 'large'}
>
<Table columns={columns} dataSource={items} pagination={false} size="small" />
<Table
columns={columns}
dataSource={items}
pagination={false}
size='small'
/>
</Modal>
);
}
@@ -126,7 +137,7 @@ export default function UpstreamRatioSync(props) {
if (res.data.success) {
const channels = res.data.data || [];
const transferData = channels.map(channel => ({
const transferData = channels.map((channel) => ({
key: channel.id,
label: channel.name,
value: channel.id,
@@ -137,9 +148,9 @@ export default function UpstreamRatioSync(props) {
setAllChannels(transferData);
// 合并已有 endpoints避免每次打开弹窗都重置
setChannelEndpoints(prev => {
setChannelEndpoints((prev) => {
const merged = { ...prev };
transferData.forEach(channel => {
transferData.forEach((channel) => {
if (!merged[channel.key]) {
merged[channel.key] = DEFAULT_ENDPOINT;
}
@@ -158,8 +169,8 @@ export default function UpstreamRatioSync(props) {
const confirmChannelSelection = () => {
const selected = allChannels
.filter(ch => selectedChannelIds.includes(ch.value))
.map(ch => ch._originalData);
.filter((ch) => selectedChannelIds.includes(ch.value))
.map((ch) => ch._originalData);
if (selected.length === 0) {
showWarning(t('请至少选择一个渠道'));
@@ -173,7 +184,7 @@ export default function UpstreamRatioSync(props) {
const fetchRatiosFromChannels = async (channelList) => {
setSyncLoading(true);
const upstreams = channelList.map(ch => ({
const upstreams = channelList.map((ch) => ({
id: ch.id,
name: ch.name,
base_url: ch.base_url,
@@ -196,9 +207,12 @@ export default function UpstreamRatioSync(props) {
const { differences = {}, test_results = [] } = res.data.data;
const errorResults = test_results.filter(r => r.status === 'error');
const errorResults = test_results.filter((r) => r.status === 'error');
if (errorResults.length > 0) {
showWarning(t('部分渠道测试失败:') + errorResults.map(r => `${r.name}: ${r.error}`).join(', '));
showWarning(
t('部分渠道测试失败:') +
errorResults.map((r) => `${r.name}: ${r.error}`).join(', '),
);
}
setDifferences(differences);
@@ -219,26 +233,29 @@ export default function UpstreamRatioSync(props) {
return ratioType === 'model_price' ? 'price' : 'ratio';
}
const selectValue = useCallback((model, ratioType, value) => {
const category = getBillingCategory(ratioType);
const selectValue = useCallback(
(model, ratioType, value) => {
const category = getBillingCategory(ratioType);
setResolutions(prev => {
const newModelRes = { ...(prev[model] || {}) };
setResolutions((prev) => {
const newModelRes = { ...(prev[model] || {}) };
Object.keys(newModelRes).forEach((rt) => {
if (getBillingCategory(rt) !== category) {
delete newModelRes[rt];
}
Object.keys(newModelRes).forEach((rt) => {
if (getBillingCategory(rt) !== category) {
delete newModelRes[rt];
}
});
newModelRes[ratioType] = value;
return {
...prev,
[model]: newModelRes,
};
});
newModelRes[ratioType] = value;
return {
...prev,
[model]: newModelRes,
};
});
}, [setResolutions]);
},
[setResolutions],
);
const applySync = async () => {
const currentRatios = {
@@ -252,9 +269,12 @@ export default function UpstreamRatioSync(props) {
const getLocalBillingCategory = (model) => {
if (currentRatios.ModelPrice[model] !== undefined) return 'price';
if (currentRatios.ModelRatio[model] !== undefined ||
if (
currentRatios.ModelRatio[model] !== undefined ||
currentRatios.CompletionRatio[model] !== undefined ||
currentRatios.CacheRatio[model] !== undefined) return 'ratio';
currentRatios.CacheRatio[model] !== undefined
)
return 'ratio';
return null;
};
@@ -272,9 +292,10 @@ export default function UpstreamRatioSync(props) {
const newCat = 'model_price' in ratios ? 'price' : 'ratio';
if (localCat && localCat !== newCat) {
const currentDesc = localCat === 'price'
? `${t('固定价格')} : ${currentRatios.ModelPrice[model]}`
: `${t('模型倍率')} : ${currentRatios.ModelRatio[model] ?? '-'}\n${t('补全倍率')} : ${currentRatios.CompletionRatio[model] ?? '-'}`;
const currentDesc =
localCat === 'price'
? `${t('固定价格')} : ${currentRatios.ModelPrice[model]}`
: `${t('模型倍率')} : ${currentRatios.ModelRatio[model] ?? '-'}\n${t('补全倍率')} : ${currentRatios.CompletionRatio[model] ?? '-'}`;
let newDesc = '';
if (newCat === 'price') {
@@ -308,80 +329,83 @@ export default function UpstreamRatioSync(props) {
await performSync(currentRatios);
};
const performSync = useCallback(async (currentRatios) => {
const finalRatios = {
ModelRatio: { ...currentRatios.ModelRatio },
CompletionRatio: { ...currentRatios.CompletionRatio },
CacheRatio: { ...currentRatios.CacheRatio },
ModelPrice: { ...currentRatios.ModelPrice },
};
const performSync = useCallback(
async (currentRatios) => {
const finalRatios = {
ModelRatio: { ...currentRatios.ModelRatio },
CompletionRatio: { ...currentRatios.CompletionRatio },
CacheRatio: { ...currentRatios.CacheRatio },
ModelPrice: { ...currentRatios.ModelPrice },
};
Object.entries(resolutions).forEach(([model, ratios]) => {
const selectedTypes = Object.keys(ratios);
const hasPrice = selectedTypes.includes('model_price');
const hasRatio = selectedTypes.some(rt => rt !== 'model_price');
Object.entries(resolutions).forEach(([model, ratios]) => {
const selectedTypes = Object.keys(ratios);
const hasPrice = selectedTypes.includes('model_price');
const hasRatio = selectedTypes.some((rt) => rt !== 'model_price');
if (hasPrice) {
delete finalRatios.ModelRatio[model];
delete finalRatios.CompletionRatio[model];
delete finalRatios.CacheRatio[model];
}
if (hasRatio) {
delete finalRatios.ModelPrice[model];
}
if (hasPrice) {
delete finalRatios.ModelRatio[model];
delete finalRatios.CompletionRatio[model];
delete finalRatios.CacheRatio[model];
}
if (hasRatio) {
delete finalRatios.ModelPrice[model];
}
Object.entries(ratios).forEach(([ratioType, value]) => {
const optionKey = ratioType
.split('_')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join('');
finalRatios[optionKey][model] = parseFloat(value);
Object.entries(ratios).forEach(([ratioType, value]) => {
const optionKey = ratioType
.split('_')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join('');
finalRatios[optionKey][model] = parseFloat(value);
});
});
});
setLoading(true);
try {
const updates = Object.entries(finalRatios).map(([key, value]) =>
API.put('/api/option/', {
key,
value: JSON.stringify(value, null, 2),
})
);
setLoading(true);
try {
const updates = Object.entries(finalRatios).map(([key, value]) =>
API.put('/api/option/', {
key,
value: JSON.stringify(value, null, 2),
}),
);
const results = await Promise.all(updates);
const results = await Promise.all(updates);
if (results.every(res => res.data.success)) {
showSuccess(t('同步成功'));
props.refresh();
if (results.every((res) => res.data.success)) {
showSuccess(t('同步成功'));
props.refresh();
setDifferences(prevDifferences => {
const newDifferences = { ...prevDifferences };
setDifferences((prevDifferences) => {
const newDifferences = { ...prevDifferences };
Object.entries(resolutions).forEach(([model, ratios]) => {
Object.keys(ratios).forEach(ratioType => {
if (newDifferences[model] && newDifferences[model][ratioType]) {
delete newDifferences[model][ratioType];
Object.entries(resolutions).forEach(([model, ratios]) => {
Object.keys(ratios).forEach((ratioType) => {
if (newDifferences[model] && newDifferences[model][ratioType]) {
delete newDifferences[model][ratioType];
if (Object.keys(newDifferences[model]).length === 0) {
delete newDifferences[model];
if (Object.keys(newDifferences[model]).length === 0) {
delete newDifferences[model];
}
}
}
});
});
return newDifferences;
});
return newDifferences;
});
setResolutions({});
} else {
showError(t('部分保存失败'));
setResolutions({});
} else {
showError(t('部分保存失败'));
}
} catch (error) {
showError(t('保存失败'));
} finally {
setLoading(false);
}
} catch (error) {
showError(t('保存失败'));
} finally {
setLoading(false);
}
}, [resolutions, props.options, props.refresh]);
},
[resolutions, props.options, props.refresh],
);
const getCurrentPageData = (dataSource) => {
const startIndex = (currentPage - 1) * pageSize;
@@ -390,12 +414,12 @@ export default function UpstreamRatioSync(props) {
};
const renderHeader = () => (
<div className="flex flex-col w-full">
<div className="flex flex-col md:flex-row justify-between items-center gap-4 w-full">
<div className="flex flex-col md:flex-row gap-2 w-full md:w-auto order-2 md:order-1">
<div className='flex flex-col w-full'>
<div className='flex flex-col md:flex-row justify-between items-center gap-4 w-full'>
<div className='flex flex-col md:flex-row gap-2 w-full md:w-auto order-2 md:order-1'>
<Button
icon={<RefreshCcw size={14} />}
className="w-full md:w-auto mt-2"
className='w-full md:w-auto mt-2'
onClick={() => {
setModalVisible(true);
if (allChannels.length === 0) {
@@ -415,20 +439,20 @@ export default function UpstreamRatioSync(props) {
type='secondary'
onClick={applySync}
disabled={!hasSelections}
className="w-full md:w-auto mt-2"
className='w-full md:w-auto mt-2'
>
{t('应用同步')}
</Button>
);
})()}
<div className="flex flex-col sm:flex-row gap-2 w-full md:w-auto mt-2">
<div className='flex flex-col sm:flex-row gap-2 w-full md:w-auto mt-2'>
<Input
prefix={<IconSearch size={14} />}
placeholder={t('搜索模型名称')}
value={searchKeyword}
onChange={setSearchKeyword}
className="w-full sm:w-64"
className='w-full sm:w-64'
showClear
/>
@@ -436,14 +460,16 @@ export default function UpstreamRatioSync(props) {
placeholder={t('按倍率类型筛选')}
value={ratioTypeFilter}
onChange={setRatioTypeFilter}
className="w-full sm:w-48"
className='w-full sm:w-48'
showClear
onClear={() => setRatioTypeFilter('')}
>
<Select.Option value="model_ratio">{t('模型倍率')}</Select.Option>
<Select.Option value="completion_ratio">{t('补全倍率')}</Select.Option>
<Select.Option value="cache_ratio">{t('缓存倍率')}</Select.Option>
<Select.Option value="model_price">{t('固定价格')}</Select.Option>
<Select.Option value='model_ratio'>{t('模型倍率')}</Select.Option>
<Select.Option value='completion_ratio'>
{t('补全倍率')}
</Select.Option>
<Select.Option value='cache_ratio'>{t('缓存倍率')}</Select.Option>
<Select.Option value='model_price'>{t('固定价格')}</Select.Option>
</Select>
</div>
</div>
@@ -457,7 +483,11 @@ export default function UpstreamRatioSync(props) {
Object.entries(differences).forEach(([model, ratioTypes]) => {
const hasPrice = 'model_price' in ratioTypes;
const hasOtherRatio = ['model_ratio', 'completion_ratio', 'cache_ratio'].some(rt => rt in ratioTypes);
const hasOtherRatio = [
'model_ratio',
'completion_ratio',
'cache_ratio',
].some((rt) => rt in ratioTypes);
const billingConflict = hasPrice && hasOtherRatio;
Object.entries(ratioTypes).forEach(([ratioType, diff]) => {
@@ -481,12 +511,13 @@ export default function UpstreamRatioSync(props) {
return dataSource;
}
return dataSource.filter(item => {
const matchesKeyword = !searchKeyword.trim() ||
return dataSource.filter((item) => {
const matchesKeyword =
!searchKeyword.trim() ||
item.model.toLowerCase().includes(searchKeyword.toLowerCase().trim());
const matchesRatioType = !ratioTypeFilter ||
item.ratioType === ratioTypeFilter;
const matchesRatioType =
!ratioTypeFilter || item.ratioType === ratioTypeFilter;
return matchesKeyword && matchesRatioType;
});
@@ -504,13 +535,17 @@ export default function UpstreamRatioSync(props) {
return (
<Empty
image={<IllustrationNoResult style={{ width: 150, height: 150 }} />}
darkModeImage={<IllustrationNoResultDark style={{ width: 150, height: 150 }} />}
darkModeImage={
<IllustrationNoResultDark style={{ width: 150, height: 150 }} />
}
description={
searchKeyword.trim()
? t('未找到匹配的模型')
: (Object.keys(differences).length === 0 ?
(hasSynced ? t('暂无差异化倍率显示') : t('请先选择同步渠道'))
: t('请先选择同步渠道'))
: Object.keys(differences).length === 0
? hasSynced
? t('暂无差异化倍率显示')
: t('请先选择同步渠道')
: t('请先选择同步渠道')
}
style={{ padding: 30 }}
/>
@@ -533,13 +568,22 @@ export default function UpstreamRatioSync(props) {
cache_ratio: t('缓存倍率'),
model_price: t('固定价格'),
};
const baseTag = <Tag color={stringToColor(text)} shape="circle">{typeMap[text] || text}</Tag>;
const baseTag = (
<Tag color={stringToColor(text)} shape='circle'>
{typeMap[text] || text}
</Tag>
);
if (record?.billingConflict) {
return (
<div className="flex items-center gap-1">
<div className='flex items-center gap-1'>
{baseTag}
<Tooltip position="top" content={t('该模型存在固定价格与倍率计费方式冲突,请确认选择')}>
<AlertTriangle size={14} className="text-yellow-500" />
<Tooltip
position='top'
content={t(
'该模型存在固定价格与倍率计费方式冲突,请确认选择',
)}
>
<AlertTriangle size={14} className='text-yellow-500' />
</Tooltip>
</div>
);
@@ -551,12 +595,19 @@ export default function UpstreamRatioSync(props) {
title: t('置信度'),
dataIndex: 'confidence',
render: (_, record) => {
const allConfident = Object.values(record.confidence || {}).every(v => v !== false);
const allConfident = Object.values(record.confidence || {}).every(
(v) => v !== false,
);
if (allConfident) {
return (
<Tooltip content={t('所有上游数据均可信')}>
<Tag color="green" shape="circle" type="light" prefixIcon={<CheckCircle size={14} />}>
<Tag
color='green'
shape='circle'
type='light'
prefixIcon={<CheckCircle size={14} />}
>
{t('可信')}
</Tag>
</Tooltip>
@@ -568,8 +619,15 @@ export default function UpstreamRatioSync(props) {
.join(', ');
return (
<Tooltip content={t('以下上游数据可能不可信:') + untrustedSources}>
<Tag color="yellow" shape="circle" type="light" prefixIcon={<AlertTriangle size={14} />}>
<Tooltip
content={t('以下上游数据可能不可信:') + untrustedSources}
>
<Tag
color='yellow'
shape='circle'
type='light'
prefixIcon={<AlertTriangle size={14} />}
>
{t('谨慎')}
</Tag>
</Tooltip>
@@ -581,7 +639,10 @@ export default function UpstreamRatioSync(props) {
title: t('当前值'),
dataIndex: 'current',
render: (text) => (
<Tag color={text !== null && text !== undefined ? 'blue' : 'default'} shape="circle">
<Tag
color={text !== null && text !== undefined ? 'blue' : 'default'}
shape='circle'
>
{text !== null && text !== undefined ? text : t('未设置')}
</Tag>
),
@@ -593,9 +654,14 @@ export default function UpstreamRatioSync(props) {
filteredDataSource.forEach((row) => {
const upstreamVal = row.upstreams?.[upName];
if (upstreamVal !== null && upstreamVal !== undefined && upstreamVal !== 'same') {
if (
upstreamVal !== null &&
upstreamVal !== undefined &&
upstreamVal !== 'same'
) {
selectableCount++;
const isSelected = resolutions[row.model]?.[row.ratioType] === upstreamVal;
const isSelected =
resolutions[row.model]?.[row.ratioType] === upstreamVal;
if (isSelected) {
selectedCount++;
}
@@ -605,9 +671,11 @@ export default function UpstreamRatioSync(props) {
return {
selectableCount,
selectedCount,
allSelected: selectableCount > 0 && selectedCount === selectableCount,
partiallySelected: selectedCount > 0 && selectedCount < selectableCount,
hasSelectableItems: selectableCount > 0
allSelected:
selectableCount > 0 && selectedCount === selectableCount,
partiallySelected:
selectedCount > 0 && selectedCount < selectableCount,
hasSelectableItems: selectableCount > 0,
};
})();
@@ -615,7 +683,11 @@ export default function UpstreamRatioSync(props) {
if (checked) {
filteredDataSource.forEach((row) => {
const upstreamVal = row.upstreams?.[upName];
if (upstreamVal !== null && upstreamVal !== undefined && upstreamVal !== 'same') {
if (
upstreamVal !== null &&
upstreamVal !== undefined &&
upstreamVal !== 'same'
) {
selectValue(row.model, row.ratioType, upstreamVal);
}
});
@@ -653,17 +725,26 @@ export default function UpstreamRatioSync(props) {
const isConfident = record.confidence?.[upName] !== false;
if (upstreamVal === null || upstreamVal === undefined) {
return <Tag color="default" shape="circle">{t('未设置')}</Tag>;
return (
<Tag color='default' shape='circle'>
{t('未设置')}
</Tag>
);
}
if (upstreamVal === 'same') {
return <Tag color="blue" shape="circle">{t('与本地相同')}</Tag>;
return (
<Tag color='blue' shape='circle'>
{t('与本地相同')}
</Tag>
);
}
const isSelected = resolutions[record.model]?.[record.ratioType] === upstreamVal;
const isSelected =
resolutions[record.model]?.[record.ratioType] === upstreamVal;
return (
<div className="flex items-center gap-2">
<div className='flex items-center gap-2'>
<Checkbox
checked={isSelected}
onChange={(e) => {
@@ -687,8 +768,11 @@ export default function UpstreamRatioSync(props) {
{upstreamVal}
</Checkbox>
{!isConfident && (
<Tooltip position='left' content={t('该数据可能不可信,请谨慎使用')}>
<AlertTriangle size={16} className="text-yellow-500" />
<Tooltip
position='left'
content={t('该数据可能不可信,请谨慎使用')}
>
<AlertTriangle size={16} className='text-yellow-500' />
</Tooltip>
)}
</div>
@@ -716,7 +800,7 @@ export default function UpstreamRatioSync(props) {
onShowSizeChange: (current, size) => {
setCurrentPage(1);
setPageSize(size);
}
},
}}
scroll={{ x: 'max-content' }}
size='middle'
@@ -726,7 +810,7 @@ export default function UpstreamRatioSync(props) {
};
const updateChannelEndpoint = useCallback((channelId, endpoint) => {
setChannelEndpoints(prev => ({ ...prev, [channelId]: endpoint }));
setChannelEndpoints((prev) => ({ ...prev, [channelId]: endpoint }));
}, []);
const handleModalClose = () => {
@@ -773,4 +857,4 @@ export default function UpstreamRatioSync(props) {
/>
</>
);
}
}