@@ -822,7 +822,9 @@ const EditChannelModal = (props) => {
822822 delete localInputs . key ;
823823 }
824824 } else {
825- localInputs . key = batch ? JSON . stringify ( keys ) : JSON . stringify ( keys [ 0 ] ) ;
825+ localInputs . key = batch
826+ ? JSON . stringify ( keys )
827+ : JSON . stringify ( keys [ 0 ] ) ;
826828 }
827829 }
828830 }
@@ -919,6 +921,56 @@ const EditChannelModal = (props) => {
919921 }
920922 } ;
921923
924+ // 密钥去重函数
925+ const deduplicateKeys = ( ) => {
926+ const currentKey = formApiRef . current ?. getValue ( 'key' ) || inputs . key || '' ;
927+
928+ if ( ! currentKey . trim ( ) ) {
929+ showInfo ( t ( '请先输入密钥' ) ) ;
930+ return ;
931+ }
932+
933+ // 按行分割密钥
934+ const keyLines = currentKey . split ( '\n' ) ;
935+ const beforeCount = keyLines . length ;
936+
937+ // 使用哈希表去重,保持原有顺序
938+ const keySet = new Set ( ) ;
939+ const deduplicatedKeys = [ ] ;
940+
941+ keyLines . forEach ( ( line ) => {
942+ const trimmedLine = line . trim ( ) ;
943+ if ( trimmedLine && ! keySet . has ( trimmedLine ) ) {
944+ keySet . add ( trimmedLine ) ;
945+ deduplicatedKeys . push ( trimmedLine ) ;
946+ }
947+ } ) ;
948+
949+ const afterCount = deduplicatedKeys . length ;
950+ const deduplicatedKeyText = deduplicatedKeys . join ( '\n' ) ;
951+
952+ // 更新表单和状态
953+ if ( formApiRef . current ) {
954+ formApiRef . current . setValue ( 'key' , deduplicatedKeyText ) ;
955+ }
956+ handleInputChange ( 'key' , deduplicatedKeyText ) ;
957+
958+ // 显示去重结果
959+ const message = t (
960+ '去重完成:去重前 {{before}} 个密钥,去重后 {{after}} 个密钥' ,
961+ {
962+ before : beforeCount ,
963+ after : afterCount ,
964+ } ,
965+ ) ;
966+
967+ if ( beforeCount === afterCount ) {
968+ showInfo ( t ( '未发现重复密钥' ) ) ;
969+ } else {
970+ showSuccess ( message ) ;
971+ }
972+ } ;
973+
922974 const addCustomModels = ( ) => {
923975 if ( customModel . trim ( ) === '' ) return ;
924976 const modelArray = customModel . split ( ',' ) . map ( ( model ) => model . trim ( ) ) ;
@@ -1014,24 +1066,41 @@ const EditChannelModal = (props) => {
10141066 </ Checkbox >
10151067 ) }
10161068 { batch && (
1017- < Checkbox
1018- disabled = { isEdit }
1019- checked = { multiToSingle }
1020- onChange = { ( ) => {
1021- setMultiToSingle ( ( prev ) => ! prev ) ;
1022- setInputs ( ( prev ) => {
1023- const newInputs = { ...prev } ;
1024- if ( ! multiToSingle ) {
1025- newInputs . multi_key_mode = multiKeyMode ;
1026- } else {
1027- delete newInputs . multi_key_mode ;
1028- }
1029- return newInputs ;
1030- } ) ;
1031- } }
1032- >
1033- { t ( '密钥聚合模式' ) }
1034- </ Checkbox >
1069+ < >
1070+ < Checkbox
1071+ disabled = { isEdit }
1072+ checked = { multiToSingle }
1073+ onChange = { ( ) => {
1074+ setMultiToSingle ( ( prev ) => {
1075+ const nextValue = ! prev ;
1076+ setInputs ( ( prevInputs ) => {
1077+ const newInputs = { ...prevInputs } ;
1078+ if ( nextValue ) {
1079+ newInputs . multi_key_mode = multiKeyMode ;
1080+ } else {
1081+ delete newInputs . multi_key_mode ;
1082+ }
1083+ return newInputs ;
1084+ } ) ;
1085+ return nextValue ;
1086+ } ) ;
1087+ } }
1088+ >
1089+ { t ( '密钥聚合模式' ) }
1090+ </ Checkbox >
1091+
1092+ { inputs . type !== 41 && (
1093+ < Button
1094+ size = 'small'
1095+ type = 'tertiary'
1096+ theme = 'outline'
1097+ onClick = { deduplicateKeys }
1098+ style = { { textDecoration : 'underline' } }
1099+ >
1100+ { t ( '密钥去重' ) }
1101+ </ Button >
1102+ ) }
1103+ </ >
10351104 ) }
10361105 </ Space >
10371106 ) : null ;
@@ -1218,7 +1287,10 @@ const EditChannelModal = (props) => {
12181287 value = { inputs . vertex_key_type || 'json' }
12191288 onChange = { ( value ) => {
12201289 // 更新设置中的 vertex_key_type
1221- handleChannelOtherSettingsChange ( 'vertex_key_type' , value ) ;
1290+ handleChannelOtherSettingsChange (
1291+ 'vertex_key_type' ,
1292+ value ,
1293+ ) ;
12221294 // 切换为 api_key 时,关闭批量与手动/文件切换,并清理已选文件
12231295 if ( value === 'api_key' ) {
12241296 setBatch ( false ) ;
@@ -1238,7 +1310,8 @@ const EditChannelModal = (props) => {
12381310 />
12391311 ) }
12401312 { batch ? (
1241- inputs . type === 41 && ( inputs . vertex_key_type || 'json' ) === 'json' ? (
1313+ inputs . type === 41 &&
1314+ ( inputs . vertex_key_type || 'json' ) === 'json' ? (
12421315 < Form . Upload
12431316 field = 'vertex_files'
12441317 label = { t ( '密钥文件 (.json)' ) }
@@ -1274,7 +1347,7 @@ const EditChannelModal = (props) => {
12741347 autoComplete = 'new-password'
12751348 onChange = { ( value ) => handleInputChange ( 'key' , value ) }
12761349 extraText = {
1277- < div className = 'flex items-center gap-2' >
1350+ < div className = 'flex items-center gap-2 flex-wrap ' >
12781351 { isEdit &&
12791352 isMultiKeyChannel &&
12801353 keyMode === 'append' && (
@@ -1302,7 +1375,8 @@ const EditChannelModal = (props) => {
13021375 )
13031376 ) : (
13041377 < >
1305- { inputs . type === 41 && ( inputs . vertex_key_type || 'json' ) === 'json' ? (
1378+ { inputs . type === 41 &&
1379+ ( inputs . vertex_key_type || 'json' ) === 'json' ? (
13061380 < >
13071381 { ! batch && (
13081382 < div className = 'flex items-center justify-between mb-3' >
0 commit comments