feat(ui): add incremental-add feedback & translations for model lists (#1218)

Front-end enhancements around “Add custom models”:

• EditChannel.js / EditTagModal.js
  – Skip models that already exist instead of blocking the action.
  – Collect actually inserted items and display:
      • Success toast: “Added N models: model1, model2 …”
      • Info toast when no new model detected.
  – Keeps UX smooth while preserving deduplication logic.

• i18n
  – en.json: added keys
      • "已新增 {{count}} 个模型:{{list}}"
      • "未发现新增模型"
  – Fixed a broken JSON string containing smart quotes to maintain valid syntax.

Result:
Users can bulk-paste model names; duplicates are silently ignored and the UI clearly lists what was incrementally appended. All messages are fully internationalised.

Closes #1218
This commit is contained in:
Apple\Apple
2025-06-13 13:49:15 +08:00
parent 0e05f725a4
commit 47531a6b93
4 changed files with 32 additions and 15 deletions

View File

@@ -8,6 +8,7 @@ import (
"github.com/samber/lo"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type Ability struct {
@@ -158,7 +159,7 @@ func (channel *Channel) AddAbilities() error {
return nil
}
for _, chunk := range lo.Chunk(abilities, 50) {
err := DB.Create(&chunk).Error
err := DB.Clauses(clause.OnConflict{DoNothing: true}).Create(&chunk).Error
if err != nil {
return err
}
@@ -224,7 +225,7 @@ func (channel *Channel) UpdateAbilities(tx *gorm.DB) error {
if len(abilities) > 0 {
for _, chunk := range lo.Chunk(abilities, 50) {
err = tx.Create(&chunk).Error
err = tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&chunk).Error
if err != nil {
if isNewTx {
tx.Rollback()

View File

@@ -1652,5 +1652,7 @@
"开启后,仅“消费”和“错误”日志将记录您的客户端 IP 地址": "After enabling, only \"consumption\" and \"error\" logs will record your client IP address",
"只有当用户设置开启IP记录时才会进行请求和错误类型日志的IP记录": "Only when the user sets IP recording, the IP recording of request and error type logs will be performed",
"设置保存成功": "Settings saved successfully",
"设置保存失败": "Settings save failed"
"设置保存失败": "Settings save failed",
"已新增 {{count}} 个模型:{{list}}": "Added {{count}} models: {{list}}",
"未发现新增模型": "No new models were added"
}

View File

@@ -385,7 +385,7 @@ const EditChannel = (props) => {
let localModels = [...inputs.models];
let localModelOptions = [...modelOptions];
let hasError = false;
const addedModels = [];
modelArray.forEach((model) => {
if (model && !localModels.includes(model)) {
@@ -395,17 +395,24 @@ const EditChannel = (props) => {
text: model,
value: model,
});
} else if (model) {
showError(t('某些模型已存在!'));
hasError = true;
addedModels.push(model);
}
});
if (hasError) return;
setModelOptions(localModelOptions);
setCustomModel('');
handleInputChange('models', localModels);
if (addedModels.length > 0) {
showSuccess(
t('已新增 {{count}} 个模型:{{list}}', {
count: addedModels.length,
list: addedModels.join(', '),
})
);
} else {
showInfo(t('未发现新增模型'));
}
};
return (

View File

@@ -229,7 +229,7 @@ const EditTagModal = (props) => {
let localModels = [...inputs.models];
let localModelOptions = [...modelOptions];
let hasError = false;
const addedModels = [];
modelArray.forEach((model) => {
// 检查模型是否已存在,且模型名称非空
@@ -241,18 +241,25 @@ const EditTagModal = (props) => {
text: model,
value: model,
});
} else if (model) {
showError('某些模型已存在!');
hasError = true;
addedModels.push(model);
}
});
if (hasError) return; // 如果有错误则终止操作
// 更新状态值
setModelOptions(localModelOptions);
setCustomModel('');
handleInputChange('models', localModels);
if (addedModels.length > 0) {
showSuccess(
t('已新增 {{count}} 个模型:{{list}}', {
count: addedModels.length,
list: addedModels.join(', '),
})
);
} else {
showInfo(t('未发现新增模型'));
}
};
return (