diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json
index b8e1afd8..ab793364 100644
--- a/web/src/i18n/locales/en.json
+++ b/web/src/i18n/locales/en.json
@@ -1687,5 +1687,6 @@
"缓存倍率": "Cache ratio",
"暂无差异化倍率显示": "No differential ratio display",
"请先选择同步渠道": "Please select the synchronization channel first",
- "与本地相同": "Same as local"
+ "与本地相同": "Same as local",
+ "未找到匹配的模型": "No matching model found"
}
\ No newline at end of file
diff --git a/web/src/pages/Setting/Ratio/UpstreamRatioSync.js b/web/src/pages/Setting/Ratio/UpstreamRatioSync.js
index aae6d9f3..f83e0cdc 100644
--- a/web/src/pages/Setting/Ratio/UpstreamRatioSync.js
+++ b/web/src/pages/Setting/Ratio/UpstreamRatioSync.js
@@ -6,7 +6,9 @@ import {
Empty,
Checkbox,
Form,
+ Input,
} from '@douyinfe/semi-ui';
+import { IconSearch } from '@douyinfe/semi-icons';
import {
RefreshCcw,
CheckSquare,
@@ -37,10 +39,16 @@ export default function UpstreamRatioSync(props) {
const [differences, setDifferences] = useState({});
const [resolutions, setResolutions] = useState({});
+ // 是否已经执行过同步
+ const [hasSynced, setHasSynced] = useState(false);
+
// 分页相关状态
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
+ // 搜索相关状态
+ const [searchKeyword, setSearchKeyword] = useState('');
+
const fetchAllChannels = async () => {
setLoading(true);
try {
@@ -114,6 +122,7 @@ export default function UpstreamRatioSync(props) {
setDifferences(differences);
setResolutions({});
+ setHasSynced(true);
if (Object.keys(differences).length === 0) {
showSuccess(t('已与上游倍率完全一致,无需同步'));
@@ -233,6 +242,15 @@ export default function UpstreamRatioSync(props) {
);
})()}
+
+ }
+ placeholder={t('搜索模型名称')}
+ value={searchKeyword}
+ onChange={setSearchKeyword}
+ className="!rounded-full w-full md:w-64 mt-2"
+ showClear
+ />
@@ -257,20 +275,37 @@ export default function UpstreamRatioSync(props) {
return tmp;
}, [differences]);
+ const filteredDataSource = useMemo(() => {
+ if (!searchKeyword.trim()) {
+ return dataSource;
+ }
+
+ const keyword = searchKeyword.toLowerCase().trim();
+ return dataSource.filter(item =>
+ item.model.toLowerCase().includes(keyword)
+ );
+ }, [dataSource, searchKeyword]);
+
const upstreamNames = useMemo(() => {
const set = new Set();
- dataSource.forEach((row) => {
+ filteredDataSource.forEach((row) => {
Object.keys(row.upstreams || {}).forEach((name) => set.add(name));
});
return Array.from(set);
- }, [dataSource]);
+ }, [filteredDataSource]);
- if (dataSource.length === 0) {
+ if (filteredDataSource.length === 0) {
return (