Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
c390734c
authored
Nov 06, 2025
by
Seefs
Committed by
GitHub
Nov 06, 2025
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: EditTagModal header && param (#2159)
parent
de250124
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
230 additions
and
10 deletions
+230
-10
controller/channel.go
+32
-8
model/channel.go
+7
-1
web/src/components/table/channels/modals/EditTagModal.jsx
+191
-1
No files found.
controller/channel.go
View file @
c390734c
...
...
@@ -649,13 +649,15 @@ func DeleteDisabledChannel(c *gin.Context) {
}
type
ChannelTag
struct
{
Tag
string
`json:"tag"`
NewTag
*
string
`json:"new_tag"`
Priority
*
int64
`json:"priority"`
Weight
*
uint
`json:"weight"`
ModelMapping
*
string
`json:"model_mapping"`
Models
*
string
`json:"models"`
Groups
*
string
`json:"groups"`
Tag
string
`json:"tag"`
NewTag
*
string
`json:"new_tag"`
Priority
*
int64
`json:"priority"`
Weight
*
uint
`json:"weight"`
ModelMapping
*
string
`json:"model_mapping"`
Models
*
string
`json:"models"`
Groups
*
string
`json:"groups"`
ParamOverride
*
string
`json:"param_override"`
HeaderOverride
*
string
`json:"header_override"`
}
func
DisableTagChannels
(
c
*
gin
.
Context
)
{
...
...
@@ -721,7 +723,29 @@ func EditTagChannels(c *gin.Context) {
})
return
}
err
=
model
.
EditChannelByTag
(
channelTag
.
Tag
,
channelTag
.
NewTag
,
channelTag
.
ModelMapping
,
channelTag
.
Models
,
channelTag
.
Groups
,
channelTag
.
Priority
,
channelTag
.
Weight
)
if
channelTag
.
ParamOverride
!=
nil
{
trimmed
:=
strings
.
TrimSpace
(
*
channelTag
.
ParamOverride
)
if
trimmed
!=
""
&&
!
json
.
Valid
([]
byte
(
trimmed
))
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
"参数覆盖必须是合法的 JSON 格式"
,
})
return
}
channelTag
.
ParamOverride
=
common
.
GetPointer
[
string
](
trimmed
)
}
if
channelTag
.
HeaderOverride
!=
nil
{
trimmed
:=
strings
.
TrimSpace
(
*
channelTag
.
HeaderOverride
)
if
trimmed
!=
""
&&
!
json
.
Valid
([]
byte
(
trimmed
))
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
"message"
:
"请求头覆盖必须是合法的 JSON 格式"
,
})
return
}
channelTag
.
HeaderOverride
=
common
.
GetPointer
[
string
](
trimmed
)
}
err
=
model
.
EditChannelByTag
(
channelTag
.
Tag
,
channelTag
.
NewTag
,
channelTag
.
ModelMapping
,
channelTag
.
Models
,
channelTag
.
Groups
,
channelTag
.
Priority
,
channelTag
.
Weight
,
channelTag
.
ParamOverride
,
channelTag
.
HeaderOverride
)
if
err
!=
nil
{
common
.
ApiError
(
c
,
err
)
return
...
...
model/channel.go
View file @
c390734c
...
...
@@ -688,7 +688,7 @@ func DisableChannelByTag(tag string) error {
return
err
}
func
EditChannelByTag
(
tag
string
,
newTag
*
string
,
modelMapping
*
string
,
models
*
string
,
group
*
string
,
priority
*
int64
,
weight
*
uint
)
error
{
func
EditChannelByTag
(
tag
string
,
newTag
*
string
,
modelMapping
*
string
,
models
*
string
,
group
*
string
,
priority
*
int64
,
weight
*
uint
,
paramOverride
*
string
,
headerOverride
*
string
)
error
{
updateData
:=
Channel
{}
shouldReCreateAbilities
:=
false
updatedTag
:=
tag
...
...
@@ -714,6 +714,12 @@ func EditChannelByTag(tag string, newTag *string, modelMapping *string, models *
if
weight
!=
nil
{
updateData
.
Weight
=
weight
}
if
paramOverride
!=
nil
{
updateData
.
ParamOverride
=
paramOverride
}
if
headerOverride
!=
nil
{
updateData
.
HeaderOverride
=
headerOverride
}
err
:=
DB
.
Model
(
&
Channel
{})
.
Where
(
"tag = ?"
,
tag
)
.
Updates
(
updateData
)
.
Error
if
err
!=
nil
{
...
...
web/src/components/table/channels/modals/EditTagModal.jsx
View file @
c390734c
...
...
@@ -45,6 +45,7 @@ import {
IconBookmark
,
IconUser
,
IconCode
,
IconSetting
,
}
from
'@douyinfe/semi-icons'
;
import
{
getChannelModels
}
from
'../../../../helpers'
;
import
{
useTranslation
}
from
'react-i18next'
;
...
...
@@ -69,6 +70,8 @@ const EditTagModal = (props) => {
model_mapping
:
null
,
groups
:
[],
models
:
[],
param_override
:
null
,
header_override
:
null
,
};
const
[
inputs
,
setInputs
]
=
useState
(
originInputs
);
const
formApiRef
=
useRef
(
null
);
...
...
@@ -190,12 +193,48 @@ const EditTagModal = (props) => {
if
(
formVals
.
models
&&
formVals
.
models
.
length
>
0
)
{
data
.
models
=
formVals
.
models
.
join
(
','
);
}
if
(
formVals
.
param_override
!==
undefined
&&
formVals
.
param_override
!==
null
)
{
if
(
typeof
formVals
.
param_override
!==
'string'
)
{
showInfo
(
'参数覆盖必须是合法的 JSON 格式!'
);
setLoading
(
false
);
return
;
}
const
trimmedParamOverride
=
formVals
.
param_override
.
trim
();
if
(
trimmedParamOverride
!==
''
&&
!
verifyJSON
(
trimmedParamOverride
))
{
showInfo
(
'参数覆盖必须是合法的 JSON 格式!'
);
setLoading
(
false
);
return
;
}
data
.
param_override
=
trimmedParamOverride
;
}
if
(
formVals
.
header_override
!==
undefined
&&
formVals
.
header_override
!==
null
)
{
if
(
typeof
formVals
.
header_override
!==
'string'
)
{
showInfo
(
'请求头覆盖必须是合法的 JSON 格式!'
);
setLoading
(
false
);
return
;
}
const
trimmedHeaderOverride
=
formVals
.
header_override
.
trim
();
if
(
trimmedHeaderOverride
!==
''
&&
!
verifyJSON
(
trimmedHeaderOverride
))
{
showInfo
(
'请求头覆盖必须是合法的 JSON 格式!'
);
setLoading
(
false
);
return
;
}
data
.
header_override
=
trimmedHeaderOverride
;
}
data
.
new_tag
=
formVals
.
new_tag
;
if
(
data
.
model_mapping
===
undefined
&&
data
.
groups
===
undefined
&&
data
.
models
===
undefined
&&
data
.
new_tag
===
undefined
data
.
new_tag
===
undefined
&&
data
.
param_override
===
undefined
&&
data
.
header_override
===
undefined
)
{
showWarning
(
'没有任何修改!'
);
setLoading
(
false
);
...
...
@@ -491,6 +530,157 @@ const EditTagModal = (props) => {
</
div
>
</
Card
>
<
Card
className=
'!rounded-2xl shadow-sm border-0 mb-6'
>
{
/* Header: Advanced Settings */
}
<
div
className=
'flex items-center mb-2'
>
<
Avatar
size=
'small'
color=
'orange'
className=
'mr-2 shadow-md'
>
<
IconSetting
size=
{
16
}
/>
</
Avatar
>
<
div
>
<
Text
className=
'text-lg font-medium'
>
{
t
(
'高级设置'
)
}
</
Text
>
<
div
className=
'text-xs text-gray-600'
>
{
t
(
'渠道的高级配置选项'
)
}
</
div
>
</
div
>
</
div
>
<
div
className=
'space-y-4'
>
<
Form
.
TextArea
field=
'param_override'
label=
{
t
(
'参数覆盖'
)
}
placeholder=
{
t
(
'此项可选,用于覆盖请求参数。不支持覆盖 stream 参数'
,
)
+
'\n'
+
t
(
'旧格式(直接覆盖):'
)
+
'\
n
{
\
n
"temperature"
:
0
,
\
n
"max_tokens"
:
1000
\
n
}
' +
'
\
n
\
n
' +
t('
新格式(支持条件判断与
json
自定义):
') +
'
\
n
{
\
n
"operations"
:
[
\
n
{
\
n
"path"
:
"temperature"
,
\
n
"mode"
:
"set"
,
\
n
"value"
:
0.7
,
\
n
"conditions"
:
[
\
n
{
\
n
"path"
:
"model"
,
\
n
"mode"
:
"prefix"
,
\
n
"value"
:
"gpt"
\
n
}
\
n
]
\
n
}
\
n
]
\
n
}
'
}
autosize
showClear
onChange=
{
(
value
)
=>
handleInputChange
(
'param_override'
,
value
)
}
extraText=
{
<
div
className=
'flex gap-2 flex-wrap'
>
<
Text
className=
'!text-semi-color-primary cursor-pointer'
onClick=
{
()
=>
handleInputChange
(
'param_override'
,
JSON
.
stringify
({
temperature
:
0
},
null
,
2
),
)
}
>
{
t
(
'旧格式模板'
)
}
</
Text
>
<
Text
className=
'!text-semi-color-primary cursor-pointer'
onClick=
{
()
=>
handleInputChange
(
'param_override'
,
JSON
.
stringify
(
{
operations
:
[
{
path
:
'temperature'
,
mode
:
'set'
,
value
:
0.7
,
conditions
:
[
{
path
:
'model'
,
mode
:
'prefix'
,
value
:
'gpt'
,
},
],
logic
:
'AND'
,
},
],
},
null
,
2
,
),
)
}
>
{
t
(
'新格式模板'
)
}
</
Text
>
<
Text
className=
'!text-semi-color-primary cursor-pointer'
onClick=
{
()
=>
handleInputChange
(
'param_override'
,
null
)
}
>
{
t
(
'不更改'
)
}
</
Text
>
</
div
>
}
/>
<
Form
.
TextArea
field=
'header_override'
label=
{
t
(
'请求头覆盖'
)
}
placeholder=
{
t
(
'此项可选,用于覆盖请求头参数'
)
+
'\n'
+
t
(
'格式示例:'
)
+
'\
n
{
\
n
"User-Agent"
:
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0"
,
\
n
"Authorization"
:
"
Bearer
{
api_key
}
"\
n
}
'
}
autosize
showClear
onChange=
{
(
value
)
=>
handleInputChange
(
'header_override'
,
value
)
}
extraText=
{
<
div
className=
'flex flex-col gap-1'
>
<
div
className=
'flex gap-2 flex-wrap items-center'
>
<
Text
className=
'!text-semi-color-primary cursor-pointer'
onClick=
{
()
=>
handleInputChange
(
'header_override'
,
JSON
.
stringify
(
{
'User-Agent'
:
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0'
,
Authorization
:
'
Bearer
{
api_key
}
'
,
},
null
,
2
,
),
)
}
>
{
t
(
'填入模板'
)
}
</
Text
>
<
Text
className=
'!text-semi-color-primary cursor-pointer'
onClick=
{
()
=>
handleInputChange
(
'header_override'
,
null
)
}
>
{
t
(
'不更改'
)
}
</
Text
>
</
div
>
<
div
>
<
Text
type=
'tertiary'
size=
'small'
>
{
t
(
'支持变量:'
)
}
</
Text
>
<
div
className=
'text-xs text-tertiary ml-2'
>
<
div
>
{
t
(
'渠道密钥'
)
}
:
{
'
{
api_key
}
'
}
</
div
>
</
div
>
</
div
>
</
div
>
}
/>
</
div
>
</
Card
>
<
Card
className=
'!rounded-2xl shadow-sm border-0'
>
{
/* Header: Group Settings */
}
<
div
className=
'flex items-center mb-2'
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment