🐛 fix(channel): remove duplicate model names in “Edit Channel” model dropdown (#1292)
• Unify the Select option structure as `{ key, label, value }`; add missing `key` to prevent duplicated rendering by Semi-UI.
• Trim and deduplicate the `models` array via `Set` inside `handleInputChange`, ensuring state always contains unique values.
• In the options-merging `useEffect`, use a `Map` keyed by `value` (after `trim`) to guarantee a unique `optionList` when combining backend data with currently selected models.
• Apply the same structure and de-duplication when:
– Fetching models from `/api/channel/models`
– Adding custom models (`addCustomModels`)
– Fetching upstream model lists (`fetchUpstreamModelList`)
• Replace obsolete `text` field with `label` in custom option objects for consistency.
No backend changes are required; the fix is entirely front-end.
Closes #1292
This commit is contained in:
@@ -111,6 +111,10 @@ const EditChannel = (props) => {
|
|||||||
const [modalImageUrl, setModalImageUrl] = useState('');
|
const [modalImageUrl, setModalImageUrl] = useState('');
|
||||||
const [isModalOpenurl, setIsModalOpenurl] = useState(false);
|
const [isModalOpenurl, setIsModalOpenurl] = useState(false);
|
||||||
const handleInputChange = (name, value) => {
|
const handleInputChange = (name, value) => {
|
||||||
|
if (name === 'models' && Array.isArray(value)) {
|
||||||
|
value = Array.from(new Set(value.map((m) => (m || '').trim())));
|
||||||
|
}
|
||||||
|
|
||||||
if (name === 'base_url' && value.endsWith('/v1')) {
|
if (name === 'base_url' && value.endsWith('/v1')) {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '警告',
|
title: '警告',
|
||||||
@@ -265,10 +269,14 @@ const EditChannel = (props) => {
|
|||||||
const fetchModels = async () => {
|
const fetchModels = async () => {
|
||||||
try {
|
try {
|
||||||
let res = await API.get(`/api/channel/models`);
|
let res = await API.get(`/api/channel/models`);
|
||||||
let localModelOptions = res.data.data.map((model) => ({
|
const localModelOptions = res.data.data.map((model) => {
|
||||||
label: model.id,
|
const id = (model.id || '').trim();
|
||||||
value: model.id,
|
return {
|
||||||
}));
|
key: id,
|
||||||
|
label: id,
|
||||||
|
value: id,
|
||||||
|
};
|
||||||
|
});
|
||||||
setOriginModelOptions(localModelOptions);
|
setOriginModelOptions(localModelOptions);
|
||||||
setFullModels(res.data.data.map((model) => model.id));
|
setFullModels(res.data.data.map((model) => model.id));
|
||||||
setBasicModels(
|
setBasicModels(
|
||||||
@@ -301,20 +309,22 @@ const EditChannel = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 使用 Map 来避免重复,以 value 为键
|
|
||||||
const modelMap = new Map();
|
const modelMap = new Map();
|
||||||
|
|
||||||
// 先添加原始模型选项
|
|
||||||
originModelOptions.forEach(option => {
|
originModelOptions.forEach(option => {
|
||||||
modelMap.set(option.value, option);
|
const v = (option.value || '').trim();
|
||||||
|
if (!modelMap.has(v)) {
|
||||||
|
modelMap.set(v, option);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 再添加当前选中的模型(如果不存在)
|
|
||||||
inputs.models.forEach(model => {
|
inputs.models.forEach(model => {
|
||||||
if (!modelMap.has(model)) {
|
const v = (model || '').trim();
|
||||||
modelMap.set(model, {
|
if (!modelMap.has(v)) {
|
||||||
label: model,
|
modelMap.set(v, {
|
||||||
value: model,
|
key: v,
|
||||||
|
label: v,
|
||||||
|
value: v,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -403,7 +413,7 @@ const EditChannel = (props) => {
|
|||||||
localModels.push(model);
|
localModels.push(model);
|
||||||
localModelOptions.push({
|
localModelOptions.push({
|
||||||
key: model,
|
key: model,
|
||||||
text: model,
|
label: model,
|
||||||
value: model,
|
value: model,
|
||||||
});
|
});
|
||||||
addedModels.push(model);
|
addedModels.push(model);
|
||||||
|
|||||||
Reference in New Issue
Block a user