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
f0886c8a
authored
Feb 22, 2026
by
Seefs
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix
parent
6b58648d
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
559 additions
and
120 deletions
+559
-120
web/src/components/table/channels/modals/ParamOverrideEditorModal.jsx
+559
-120
No files found.
web/src/components/table/channels/modals/ParamOverrideEditorModal.jsx
View file @
f0886c8a
...
...
@@ -20,10 +20,10 @@ For commercial licensing, please contact support@quantumnous.com
import
React
,
{
useCallback
,
useEffect
,
useMemo
,
useState
}
from
'react'
;
import
{
useTranslation
}
from
'react-i18next'
;
import
{
Banner
,
Button
,
Card
,
Col
,
Collapse
,
Input
,
Modal
,
Row
,
...
...
@@ -31,6 +31,7 @@ import {
Space
,
Switch
,
Tag
,
TextArea
,
Typography
,
}
from
'@douyinfe/semi-ui'
;
import
{
IconDelete
,
IconPlus
}
from
'@douyinfe/semi-icons'
;
...
...
@@ -204,6 +205,11 @@ const OPERATION_TEMPLATE = {
],
};
const
TEMPLATE_LIBRARY_OPTIONS
=
[
{
label
:
'Template · Operations'
,
value
:
'operations'
},
{
label
:
'Template · Legacy Object'
,
value
:
'legacy'
},
];
let
localIdSeed
=
0
;
const
nextLocalId
=
()
=>
`param_override_
${
Date
.
now
()}
_
${
localIdSeed
++
}
`
;
...
...
@@ -274,6 +280,28 @@ const normalizeOperation = (operation = {}) => ({
const
createDefaultOperation
=
()
=>
normalizeOperation
({
mode
:
'set'
});
const
getOperationSummary
=
(
operation
=
{},
index
=
0
)
=>
{
const
mode
=
operation
.
mode
||
'set'
;
if
(
mode
===
'sync_fields'
)
{
const
from
=
String
(
operation
.
from
||
''
).
trim
();
const
to
=
String
(
operation
.
to
||
''
).
trim
();
return
`
${
index
+
1
}
.
${
mode
}
·
${
from
||
to
||
'-'
}
`
;
}
const
path
=
String
(
operation
.
path
||
''
).
trim
();
const
from
=
String
(
operation
.
from
||
''
).
trim
();
const
to
=
String
(
operation
.
to
||
''
).
trim
();
return
`
${
index
+
1
}
.
${
mode
}
·
${
path
||
from
||
to
||
'-'
}
`
;
};
const
getOperationModeTagColor
=
(
mode
=
'set'
)
=>
{
if
(
mode
.
includes
(
'header'
))
return
'cyan'
;
if
(
mode
.
includes
(
'replace'
)
||
mode
.
includes
(
'trim'
))
return
'violet'
;
if
(
mode
.
includes
(
'copy'
)
||
mode
.
includes
(
'move'
))
return
'blue'
;
if
(
mode
.
includes
(
'error'
)
||
mode
.
includes
(
'prune'
))
return
'red'
;
if
(
mode
.
includes
(
'sync'
))
return
'green'
;
return
'grey'
;
};
const
parseInitialState
=
(
rawValue
)
=>
{
const
text
=
typeof
rawValue
===
'string'
?
rawValue
:
''
;
const
trimmed
=
text
.
trim
();
...
...
@@ -439,6 +467,10 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
const
[
operations
,
setOperations
]
=
useState
([
createDefaultOperation
()]);
const
[
jsonText
,
setJsonText
]
=
useState
(
''
);
const
[
jsonError
,
setJsonError
]
=
useState
(
''
);
const
[
operationSearch
,
setOperationSearch
]
=
useState
(
''
);
const
[
selectedOperationId
,
setSelectedOperationId
]
=
useState
(
''
);
const
[
expandedConditionMap
,
setExpandedConditionMap
]
=
useState
({});
const
[
templateLibraryKey
,
setTemplateLibraryKey
]
=
useState
(
'operations'
);
useEffect
(()
=>
{
if
(
!
visible
)
return
;
...
...
@@ -449,13 +481,73 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
setOperations
(
nextState
.
operations
);
setJsonText
(
nextState
.
jsonText
);
setJsonError
(
nextState
.
jsonError
);
setOperationSearch
(
''
);
setSelectedOperationId
(
nextState
.
operations
[
0
]?.
id
||
''
);
setExpandedConditionMap
({});
setTemplateLibraryKey
(
nextState
.
visualMode
===
'legacy'
?
'legacy'
:
'operations'
,
);
},
[
visible
,
value
]);
useEffect
(()
=>
{
if
(
operations
.
length
===
0
)
{
setSelectedOperationId
(
''
);
return
;
}
if
(
!
operations
.
some
((
item
)
=>
item
.
id
===
selectedOperationId
))
{
setSelectedOperationId
(
operations
[
0
].
id
);
}
},
[
operations
,
selectedOperationId
]);
useEffect
(()
=>
{
setTemplateLibraryKey
(
visualMode
===
'legacy'
?
'legacy'
:
'operations'
);
},
[
visualMode
]);
const
operationCount
=
useMemo
(
()
=>
operations
.
filter
((
item
)
=>
!
isOperationBlank
(
item
)).
length
,
[
operations
],
);
const
filteredOperations
=
useMemo
(()
=>
{
const
keyword
=
operationSearch
.
trim
().
toLowerCase
();
if
(
!
keyword
)
return
operations
;
return
operations
.
filter
((
operation
)
=>
{
const
searchableText
=
[
operation
.
mode
,
operation
.
path
,
operation
.
from
,
operation
.
to
,
operation
.
value_text
,
]
.
filter
(
Boolean
)
.
join
(
' '
)
.
toLowerCase
();
return
searchableText
.
includes
(
keyword
);
});
},
[
operationSearch
,
operations
]);
const
selectedOperation
=
useMemo
(
()
=>
operations
.
find
((
operation
)
=>
operation
.
id
===
selectedOperationId
),
[
operations
,
selectedOperationId
],
);
const
selectedOperationIndex
=
useMemo
(
()
=>
operations
.
findIndex
((
operation
)
=>
operation
.
id
===
selectedOperationId
),
[
operations
,
selectedOperationId
],
);
const
topOperationModes
=
useMemo
(()
=>
{
const
counts
=
operations
.
reduce
((
acc
,
operation
)
=>
{
const
mode
=
operation
.
mode
||
'set'
;
acc
[
mode
]
=
(
acc
[
mode
]
||
0
)
+
1
;
return
acc
;
},
{});
return
Object
.
entries
(
counts
)
.
sort
((
a
,
b
)
=>
b
[
1
]
-
a
[
1
])
.
slice
(
0
,
4
);
},
[
operations
]);
const
buildVisualJson
=
useCallback
(()
=>
{
if
(
visualMode
===
'legacy'
)
{
const
trimmed
=
legacyValue
.
trim
();
...
...
@@ -545,8 +637,10 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
if
(
editMode
===
'visual'
)
return
;
const
trimmed
=
jsonText
.
trim
();
if
(
!
trimmed
)
{
const
fallback
=
createDefaultOperation
();
setVisualMode
(
'operations'
);
setOperations
([
createDefaultOperation
()]);
setOperations
([
fallback
]);
setSelectedOperationId
(
fallback
.
id
);
setLegacyValue
(
''
);
setJsonError
(
''
);
setEditMode
(
'visual'
);
...
...
@@ -563,21 +657,24 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
!
Array
.
isArray
(
parsed
)
&&
Array
.
isArray
(
parsed
.
operations
)
)
{
setVisualMode
(
'operations'
);
setOperations
(
const
nextOperations
=
parsed
.
operations
.
length
>
0
?
parsed
.
operations
.
map
(
normalizeOperation
)
:
[
createDefaultOperation
()],
);
:
[
createDefaultOperation
()];
setVisualMode
(
'operations'
);
setOperations
(
nextOperations
);
setSelectedOperationId
(
nextOperations
[
0
]?.
id
||
''
);
setLegacyValue
(
''
);
setJsonError
(
''
);
setEditMode
(
'visual'
);
return
;
}
if
(
parsed
&&
typeof
parsed
===
'object'
&&
!
Array
.
isArray
(
parsed
))
{
const
fallback
=
createDefaultOperation
();
setVisualMode
(
'legacy'
);
setLegacyValue
(
JSON
.
stringify
(
parsed
,
null
,
2
));
setOperations
([
createDefaultOperation
()]);
setOperations
([
fallback
]);
setSelectedOperationId
(
fallback
.
id
);
setJsonError
(
''
);
setEditMode
(
'visual'
);
return
;
...
...
@@ -587,27 +684,54 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
const
setOldTemplate
=
()
=>
{
const
text
=
JSON
.
stringify
(
LEGACY_TEMPLATE
,
null
,
2
);
const
fallback
=
createDefaultOperation
();
setVisualMode
(
'legacy'
);
setLegacyValue
(
text
);
setOperations
([
fallback
]);
setSelectedOperationId
(
fallback
.
id
);
setExpandedConditionMap
({});
setJsonText
(
text
);
setJsonError
(
''
);
setEditMode
(
'visual'
);
setTemplateLibraryKey
(
'legacy'
);
};
const
setNewTemplate
=
()
=>
{
const
nextOperations
=
OPERATION_TEMPLATE
.
operations
.
map
(
normalizeOperation
);
setVisualMode
(
'operations'
);
setOperations
(
OPERATION_TEMPLATE
.
operations
.
map
(
normalizeOperation
));
setOperations
(
nextOperations
);
setSelectedOperationId
(
nextOperations
[
0
]?.
id
||
''
);
setExpandedConditionMap
({});
setJsonText
(
JSON
.
stringify
(
OPERATION_TEMPLATE
,
null
,
2
));
setJsonError
(
''
);
setEditMode
(
'visual'
);
setTemplateLibraryKey
(
'operations'
);
};
const
clearValue
=
()
=>
{
const
fallback
=
createDefaultOperation
();
setVisualMode
(
'operations'
);
setLegacyValue
(
''
);
setOperations
([
createDefaultOperation
()]);
setOperations
([
fallback
]);
setSelectedOperationId
(
fallback
.
id
);
setExpandedConditionMap
({});
setJsonText
(
''
);
setJsonError
(
''
);
setTemplateLibraryKey
(
'operations'
);
};
const
applyTemplateFromLibrary
=
()
=>
{
if
(
templateLibraryKey
===
'legacy'
)
{
setOldTemplate
();
return
;
}
setNewTemplate
();
};
const
resetEditorState
=
()
=>
{
clearValue
();
setEditMode
(
'visual'
);
};
const
updateOperation
=
(
operationId
,
patch
)
=>
{
...
...
@@ -619,10 +743,13 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
};
const
addOperation
=
()
=>
{
setOperations
((
prev
)
=>
[...
prev
,
createDefaultOperation
()]);
const
created
=
createDefaultOperation
();
setOperations
((
prev
)
=>
[...
prev
,
created
]);
setSelectedOperationId
(
created
.
id
);
};
const
duplicateOperation
=
(
operationId
)
=>
{
let
insertedId
=
''
;
setOperations
((
prev
)
=>
{
const
index
=
prev
.
findIndex
((
item
)
=>
item
.
id
===
operationId
);
if
(
index
<
0
)
return
prev
;
...
...
@@ -643,10 +770,14 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
pass_missing_key
:
condition
.
pass_missing_key
,
})),
});
insertedId
=
cloned
.
id
;
const
next
=
[...
prev
];
next
.
splice
(
index
+
1
,
0
,
cloned
);
return
next
;
});
if
(
insertedId
)
{
setSelectedOperationId
(
insertedId
);
}
};
const
removeOperation
=
(
operationId
)
=>
{
...
...
@@ -654,19 +785,32 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
if
(
prev
.
length
<=
1
)
return
[
createDefaultOperation
()];
return
prev
.
filter
((
item
)
=>
item
.
id
!==
operationId
);
});
setExpandedConditionMap
((
prev
)
=>
{
if
(
!
Object
.
prototype
.
hasOwnProperty
.
call
(
prev
,
operationId
))
{
return
prev
;
}
const
next
=
{
...
prev
};
delete
next
[
operationId
];
return
next
;
});
};
const
addCondition
=
(
operationId
)
=>
{
const
createdCondition
=
createDefaultCondition
();
setOperations
((
prev
)
=>
prev
.
map
((
operation
)
=>
operation
.
id
===
operationId
?
{
...
operation
,
conditions
:
[...(
operation
.
conditions
||
[]),
create
DefaultCondition
()
],
conditions
:
[...(
operation
.
conditions
||
[]),
create
dCondition
],
}
:
operation
,
),
);
setExpandedConditionMap
((
prev
)
=>
({
...
prev
,
[
operationId
]:
[...(
prev
[
operationId
]
||
[]),
createdCondition
.
id
],
}));
};
const
updateCondition
=
(
operationId
,
conditionId
,
patch
)
=>
{
...
...
@@ -697,8 +841,50 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
};
}),
);
setExpandedConditionMap
((
prev
)
=>
({
...
prev
,
[
operationId
]:
(
prev
[
operationId
]
||
[]).
filter
(
(
id
)
=>
id
!==
conditionId
,
),
}));
};
const
selectedConditionKeys
=
useMemo
(
()
=>
expandedConditionMap
[
selectedOperationId
]
||
[],
[
expandedConditionMap
,
selectedOperationId
],
);
const
handleConditionCollapseChange
=
useCallback
(
(
operationId
,
activeKeys
)
=>
{
const
keys
=
(
Array
.
isArray
(
activeKeys
)
?
activeKeys
:
[
activeKeys
]
).
filter
(
Boolean
);
setExpandedConditionMap
((
prev
)
=>
({
...
prev
,
[
operationId
]:
keys
,
}));
},
[],
);
const
expandAllSelectedConditions
=
useCallback
(()
=>
{
if
(
!
selectedOperationId
||
!
selectedOperation
)
return
;
setExpandedConditionMap
((
prev
)
=>
({
...
prev
,
[
selectedOperationId
]:
(
selectedOperation
.
conditions
||
[]).
map
(
(
condition
)
=>
condition
.
id
,
),
}));
},
[
selectedOperation
,
selectedOperationId
]);
const
collapseAllSelectedConditions
=
useCallback
(()
=>
{
if
(
!
selectedOperationId
)
return
;
setExpandedConditionMap
((
prev
)
=>
({
...
prev
,
[
selectedOperationId
]:
[],
}));
},
[
selectedOperationId
]);
const
handleJsonChange
=
(
nextValue
)
=>
{
setJsonText
(
nextValue
);
const
trimmed
=
String
(
nextValue
||
''
).
trim
();
...
...
@@ -761,21 +947,13 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
<
Modal
title=
{
t
(
'参数覆盖'
)
}
visible=
{
visible
}
width=
{
98
0
}
width=
{
112
0
}
onCancel=
{
onCancel
}
onOk=
{
handleSave
}
okText=
{
t
(
'保存'
)
}
cancelText=
{
t
(
'取消'
)
}
>
<
Space
vertical
align=
'start'
spacing=
{
12
}
style=
{
{
width
:
'100%'
}
}
>
<
Banner
fullMode=
{
false
}
type=
'info'
description=
{
t
(
'支持旧格式直接覆盖,也支持新格式 operations 条件编辑;可在可视化和 JSON 之间双向切换。'
,
)
}
/>
<
Space
wrap
>
<
Button
type=
{
editMode
===
'visual'
?
'primary'
:
'tertiary'
}
...
...
@@ -789,32 +967,24 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
>
{
t
(
'JSON 模式'
)
}
</
Button
>
<
Button
onClick=
{
setOldTemplate
}
>
{
t
(
'旧格式模板'
)
}
</
Button
>
<
Button
onClick=
{
setNewTemplate
}
>
{
t
(
'新格式模板'
)
}
</
Button
>
<
Button
onClick=
{
clearValue
}
>
{
t
(
'不更改'
)
}
</
Button
>
<
Select
value=
{
templateLibraryKey
}
optionList=
{
TEMPLATE_LIBRARY_OPTIONS
}
onChange=
{
(
nextValue
)
=>
setTemplateLibraryKey
(
nextValue
||
'operations'
)
}
style=
{
{
width
:
240
}
}
/>
<
Button
onClick=
{
applyTemplateFromLibrary
}
>
{
t
(
'应用模板'
)
}
</
Button
>
<
Button
onClick=
{
resetEditorState
}
>
{
t
(
'重置'
)
}
</
Button
>
</
Space
>
{
editMode
===
'visual'
?
(
<
div
style=
{
{
width
:
'100%'
}
}
>
<
Space
wrap
style=
{
{
marginBottom
:
12
}
}
>
<
Button
type=
{
visualMode
===
'operations'
?
'primary'
:
'tertiary'
}
onClick=
{
()
=>
setVisualMode
(
'operations'
)
}
>
{
t
(
'新格式模板'
)
}
</
Button
>
<
Button
type=
{
visualMode
===
'legacy'
?
'primary'
:
'tertiary'
}
onClick=
{
()
=>
setVisualMode
(
'legacy'
)
}
>
{
t
(
'旧格式模板'
)
}
</
Button
>
</
Space
>
{
visualMode
===
'legacy'
?
(
<
div
>
<
Text
className=
'mb-2 block'
>
{
t
(
'旧格式(直接覆盖):'
)
}
</
Text
>
<
Input
.
TextArea
<
TextArea
value=
{
legacyValue
}
autosize=
{
{
minRows
:
10
,
maxRows
:
20
}
}
placeholder=
{
JSON
.
stringify
(
LEGACY_TEMPLATE
,
null
,
2
)
}
...
...
@@ -830,48 +1000,190 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
<
div
className=
'flex items-center justify-between mb-3'
>
<
Space
>
<
Text
>
{
t
(
'新格式(支持条件判断与json自定义):'
)
}
</
Text
>
<
Tag
color=
'cyan'
>
{
`${t('规则')}: ${operationCount}`
}
</
Tag
>
<
Tag
color=
'cyan'
>
{
`${t('规则')}: ${operationCount}`
}
</
Tag
>
</
Space
>
<
Button
icon=
{
<
IconPlus
/>
}
onClick=
{
addOperation
}
>
{
t
(
'新增规则'
)
}
</
Button
>
</
div
>
<
Space
vertical
spacing=
{
8
}
style=
{
{
width
:
'100%'
}
}
>
{
operations
.
map
((
operation
,
index
)
=>
{
const
mode
=
operation
.
mode
||
'set'
;
<
Row
gutter=
{
12
}
>
<
Col
xs=
{
24
}
md=
{
8
}
>
<
Card
className=
'!rounded-2xl !border-0 h-full'
bodyStyle=
{
{
padding
:
12
,
background
:
'var(--semi-color-fill-0)'
,
display
:
'flex'
,
flexDirection
:
'column'
,
gap
:
10
,
minHeight
:
520
,
}
}
>
<
div
className=
'flex items-center justify-between'
>
<
Text
strong
>
{
t
(
'规则导航'
)
}
</
Text
>
<
Tag
color=
'grey'
>
{
`${operationCount}/${operations.length}`
}
</
Tag
>
</
div
>
{
topOperationModes
.
length
>
0
?
(
<
Space
wrap
spacing=
{
6
}
>
{
topOperationModes
.
map
(([
mode
,
count
])
=>
(
<
Tag
key=
{
`mode_stat_${mode}`
}
size=
'small'
color=
{
getOperationModeTagColor
(
mode
)
}
>
{
`${mode} · ${count}`
}
</
Tag
>
))
}
</
Space
>
)
:
null
}
<
Input
value=
{
operationSearch
}
placeholder=
{
t
(
'搜索规则(mode/path/from/to)'
)
}
onChange=
{
(
nextValue
)
=>
setOperationSearch
(
nextValue
||
''
)
}
showClear
/>
<
div
className=
'overflow-auto'
style=
{
{
flex
:
1
,
minHeight
:
320
,
paddingRight
:
2
}
}
>
{
filteredOperations
.
length
===
0
?
(
<
Text
type=
'tertiary'
size=
'small'
>
{
t
(
'没有匹配的规则'
)
}
</
Text
>
)
:
(
<
div
style=
{
{
display
:
'flex'
,
flexDirection
:
'column'
,
gap
:
8
,
width
:
'100%'
,
}
}
>
{
filteredOperations
.
map
((
operation
)
=>
{
const
index
=
operations
.
findIndex
(
(
item
)
=>
item
.
id
===
operation
.
id
,
);
const
isActive
=
operation
.
id
===
selectedOperationId
;
return
(
<
div
key=
{
operation
.
id
}
role=
'button'
tabIndex=
{
0
}
onClick=
{
()
=>
setSelectedOperationId
(
operation
.
id
)
}
onKeyDown=
{
(
event
)
=>
{
if
(
event
.
key
===
'Enter'
||
event
.
key
===
' '
)
{
event
.
preventDefault
();
setSelectedOperationId
(
operation
.
id
);
}
}
}
className=
'w-full rounded-xl px-3 py-3 cursor-pointer transition-colors'
style=
{
{
background
:
isActive
?
'var(--semi-color-primary-light-default)'
:
'var(--semi-color-bg-2)'
,
border
:
isActive
?
'1px solid var(--semi-color-primary)'
:
'1px solid var(--semi-color-border)'
,
}
}
>
<
div
className=
'flex items-start justify-between gap-2'
>
<
div
>
<
Text
strong
>
{
`#${index + 1}`
}
</
Text
>
<
Text
type=
'tertiary'
size=
'small'
className=
'block mt-1'
>
{
getOperationSummary
(
operation
,
index
)
}
</
Text
>
</
div
>
<
Tag
size=
'small'
color=
'grey'
>
{
(
operation
.
conditions
||
[]).
length
}
</
Tag
>
</
div
>
<
Space
spacing=
{
6
}
style=
{
{
marginTop
:
8
}
}
>
<
Tag
size=
'small'
color=
{
getOperationModeTagColor
(
operation
.
mode
||
'set'
,
)
}
>
{
operation
.
mode
||
'set'
}
</
Tag
>
<
Text
type=
'tertiary'
size=
'small'
>
{
t
(
'条件'
)
}
</
Text
>
</
Space
>
</
div
>
);
})
}
</
div
>
)
}
</
div
>
</
Card
>
</
Col
>
<
Col
xs=
{
24
}
md=
{
16
}
>
{
selectedOperation
?
(
(()
=>
{
const
mode
=
selectedOperation
.
mode
||
'set'
;
const
meta
=
MODE_META
[
mode
]
||
MODE_META
.
set
;
const
conditions
=
o
peration
.
conditions
||
[];
const
conditions
=
selectedO
peration
.
conditions
||
[];
const
syncFromTarget
=
mode
===
'sync_fields'
?
parseSyncTargetSpec
(
o
peration
.
from
)
?
parseSyncTargetSpec
(
selectedO
peration
.
from
)
:
null
;
const
syncToTarget
=
mode
===
'sync_fields'
?
parseSyncTargetSpec
(
o
peration
.
to
)
?
parseSyncTargetSpec
(
selectedO
peration
.
to
)
:
null
;
return
(
<
Card
key=
{
operation
.
id
}
className=
'!rounded-xl border'
>
<
div
className=
'flex items-center justify-between mb-2'
>
<
Card
className=
'!rounded-2xl !border-0'
bodyStyle=
{
{
padding
:
14
,
background
:
'var(--semi-color-fill-0)'
,
}
}
>
<
div
className=
'flex items-center justify-between mb-3'
>
<
Space
>
<
Tag
>
{
`#${index + 1}`
}
</
Tag
>
<
Text
>
{
mode
}
</
Text
>
<
Tag
color=
'blue'
>
{
`#${selectedOperationIndex + 1}`
}
</
Tag
>
<
Text
strong
>
{
getOperationSummary
(
selectedOperation
,
selectedOperationIndex
,
)
}
</
Text
>
</
Space
>
<
Space
>
<
Button
size=
'small'
type=
'tertiary'
onClick=
{
()
=>
duplicateOperation
(
operation
.
id
)
}
onClick=
{
()
=>
duplicateOperation
(
selectedOperation
.
id
)
}
>
{
t
(
'复制'
)
}
</
Button
>
<
Button
theme=
'borderless
'
size=
'small
'
type=
'danger'
theme=
'borderless'
icon=
{
<
IconDelete
/>
}
onClick=
{
()
=>
removeOperation
(
operation
.
id
)
}
onClick=
{
()
=>
removeOperation
(
selectedOperation
.
id
)
}
/>
</
Space
>
</
div
>
...
...
@@ -885,7 +1197,9 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
value=
{
mode
}
optionList=
{
OPERATION_MODE_OPTIONS
}
onChange=
{
(
nextMode
)
=>
updateOperation
(
operation
.
id
,
{
mode
:
nextMode
})
updateOperation
(
selectedOperation
.
id
,
{
mode
:
nextMode
,
})
}
style=
{
{
width
:
'100%'
}
}
/>
...
...
@@ -893,10 +1207,12 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
{
meta
.
path
||
meta
.
pathOptional
?
(
<
Col
xs=
{
24
}
md=
{
16
}
>
<
Text
type=
'tertiary'
size=
'small'
>
{
meta
.
pathOptional
?
'path (optional)'
:
'path'
}
{
meta
.
pathOptional
?
'path (optional)'
:
'path'
}
</
Text
>
<
Input
value=
{
o
peration
.
path
}
value=
{
selectedO
peration
.
path
}
placeholder=
{
mode
.
includes
(
'header'
)
?
'X-Debug-Mode'
...
...
@@ -905,32 +1221,42 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
:
'temperature'
}
onChange=
{
(
nextValue
)
=>
updateOperation
(
o
peration
.
id
,
{
updateOperation
(
selectedO
peration
.
id
,
{
path
:
nextValue
,
})
}
/>
<
Space
wrap
style=
{
{
marginTop
:
6
}
}
>
{
OPERATION_PATH_SUGGESTIONS
.
map
((
pathItem
)
=>
(
{
OPERATION_PATH_SUGGESTIONS
.
map
(
(
pathItem
)
=>
(
<
Tag
key=
{
`${o
peration.id}_${pathItem}`
}
key=
{
`${selectedO
peration.id}_${pathItem}`
}
size=
'small'
color=
'grey'
className=
'cursor-pointer'
onClick=
{
()
=>
updateOperation
(
operation
.
id
,
{
updateOperation
(
selectedOperation
.
id
,
{
path
:
pathItem
,
})
},
)
}
>
{
pathItem
}
</
Tag
>
))
}
),
)
}
</
Space
>
</
Col
>
)
:
null
}
</
Row
>
<
Text
type=
'tertiary'
size=
'small'
className=
'mt-1 block'
>
<
Text
type=
'tertiary'
size=
'small'
className=
'mt-1 block'
>
{
MODE_DESCRIPTIONS
[
mode
]
||
''
}
</
Text
>
...
...
@@ -939,12 +1265,12 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
<
Text
type=
'tertiary'
size=
'small'
>
value (JSON or plain text)
</
Text
>
<
Input
.
TextArea
value=
{
o
peration
.
value_text
}
<
TextArea
value=
{
selectedO
peration
.
value_text
}
autosize=
{
{
minRows
:
1
,
maxRows
:
4
}
}
placeholder=
'0.7'
onChange=
{
(
nextValue
)
=>
updateOperation
(
o
peration
.
id
,
{
updateOperation
(
selectedO
peration
.
id
,
{
value_text
:
nextValue
,
})
}
...
...
@@ -955,16 +1281,22 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
{
meta
.
keepOrigin
?
(
<
div
className=
'mt-2'
>
<
Switch
checked=
{
operation
.
keep_origin
}
checked=
{
Boolean
(
selectedOperation
.
keep_origin
,
)
}
checkedText=
{
t
(
'开'
)
}
uncheckedText=
{
t
(
'关'
)
}
onChange=
{
(
nextValue
)
=>
updateOperation
(
o
peration
.
id
,
{
updateOperation
(
selectedO
peration
.
id
,
{
keep_origin
:
nextValue
,
})
}
/>
<
Text
type=
'tertiary'
size=
'small'
className=
'ml-2'
>
<
Text
type=
'tertiary'
size=
'small'
className=
'ml-2'
>
keep_origin
</
Text
>
</
div
>
...
...
@@ -986,24 +1318,30 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
optionList=
{
SYNC_TARGET_TYPE_OPTIONS
}
style=
{
{
width
:
120
}
}
onChange=
{
(
nextType
)
=>
updateOperation
(
operation
.
id
,
{
updateOperation
(
selectedOperation
.
id
,
{
from
:
buildSyncTargetSpec
(
nextType
,
syncFromTarget
?.
key
||
''
,
),
})
},
)
}
/>
<
Input
value=
{
syncFromTarget
?.
key
||
''
}
placeholder=
'session_id'
onChange=
{
(
nextKey
)
=>
updateOperation
(
operation
.
id
,
{
updateOperation
(
selectedOperation
.
id
,
{
from
:
buildSyncTargetSpec
(
syncFromTarget
?.
type
||
'json'
,
nextKey
,
),
})
},
)
}
/>
</
div
>
...
...
@@ -1018,24 +1356,30 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
optionList=
{
SYNC_TARGET_TYPE_OPTIONS
}
style=
{
{
width
:
120
}
}
onChange=
{
(
nextType
)
=>
updateOperation
(
operation
.
id
,
{
updateOperation
(
selectedOperation
.
id
,
{
to
:
buildSyncTargetSpec
(
nextType
,
syncToTarget
?.
key
||
''
,
),
})
},
)
}
/>
<
Input
value=
{
syncToTarget
?.
key
||
''
}
placeholder=
'prompt_cache_key'
onChange=
{
(
nextKey
)
=>
updateOperation
(
operation
.
id
,
{
updateOperation
(
selectedOperation
.
id
,
{
to
:
buildSyncTargetSpec
(
syncToTarget
?.
type
||
'json'
,
nextKey
,
),
})
},
)
}
/>
</
div
>
...
...
@@ -1047,26 +1391,30 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
color=
'cyan'
className=
'cursor-pointer'
onClick=
{
()
=>
updateOperation
(
o
peration
.
id
,
{
updateOperation
(
selectedO
peration
.
id
,
{
from
:
'header:session_id'
,
to
:
'json:prompt_cache_key'
,
})
}
>
{
'header:session_id -> json:prompt_cache_key'
}
{
'header:session_id -> json:prompt_cache_key'
}
</
Tag
>
<
Tag
size=
'small'
color=
'cyan'
className=
'cursor-pointer'
onClick=
{
()
=>
updateOperation
(
o
peration
.
id
,
{
updateOperation
(
selectedO
peration
.
id
,
{
from
:
'json:prompt_cache_key'
,
to
:
'header:session_id'
,
})
}
>
{
'json:prompt_cache_key -> header:session_id'
}
{
'json:prompt_cache_key -> header:session_id'
}
</
Tag
>
</
Space
>
</
div
>
...
...
@@ -1078,14 +1426,14 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
from
</
Text
>
<
Input
value=
{
o
peration
.
from
}
value=
{
selectedO
peration
.
from
}
placeholder=
{
mode
.
includes
(
'header'
)
?
'Authorization'
:
'model'
}
onChange=
{
(
nextValue
)
=>
updateOperation
(
o
peration
.
id
,
{
updateOperation
(
selectedO
peration
.
id
,
{
from
:
nextValue
,
})
}
...
...
@@ -1098,14 +1446,16 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
to
</
Text
>
<
Input
value=
{
o
peration
.
to
}
value=
{
selectedO
peration
.
to
}
placeholder=
{
mode
.
includes
(
'header'
)
?
'X-Upstream-Auth'
:
'original_model'
}
onChange=
{
(
nextValue
)
=>
updateOperation
(
operation
.
id
,
{
to
:
nextValue
})
updateOperation
(
selectedOperation
.
id
,
{
to
:
nextValue
,
})
}
/>
</
Col
>
...
...
@@ -1113,31 +1463,54 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
</
Row
>
)
:
null
}
<
div
className=
'mt-3 border rounded-lg p-2'
>
<
div
className=
'mt-3 rounded-xl p-2'
style=
{
{
background
:
'rgba(127, 127, 127, 0.08)'
,
}
}
>
<
div
className=
'flex items-center justify-between mb-2'
>
<
Space
>
<
Text
>
{
t
(
'条件'
)
}
</
Text
>
<
Select
value=
{
o
peration
.
logic
||
'OR'
}
value=
{
selectedO
peration
.
logic
||
'OR'
}
optionList=
{
[
{
label
:
'OR'
,
value
:
'OR'
},
{
label
:
'AND'
,
value
:
'AND'
},
]
}
style=
{
{
width
:
96
}
}
onChange=
{
(
nextValue
)
=>
updateOperation
(
o
peration
.
id
,
{
updateOperation
(
selectedO
peration
.
id
,
{
logic
:
nextValue
,
})
}
/>
</
Space
>
<
Space
spacing=
{
6
}
>
<
Button
size=
'small'
type=
'tertiary'
onClick=
{
expandAllSelectedConditions
}
>
{
t
(
'全部展开'
)
}
</
Button
>
<
Button
size=
'small'
type=
'tertiary'
onClick=
{
collapseAllSelectedConditions
}
>
{
t
(
'全部收起'
)
}
</
Button
>
<
Button
icon=
{
<
IconPlus
/>
}
size=
'small'
onClick=
{
()
=>
addCondition
(
operation
.
id
)
}
onClick=
{
()
=>
addCondition
(
selectedOperation
.
id
)
}
>
{
t
(
'新增条件'
)
}
</
Button
>
</
Space
>
</
div
>
{
conditions
.
length
===
0
?
(
...
...
@@ -1145,28 +1518,54 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
{
t
(
'没有条件时,默认总是执行该操作。'
)
}
</
Text
>
)
:
(
<
Space
vertical
spacing=
{
8
}
style=
{
{
width
:
'100%'
}
}
>
{
conditions
.
map
((
condition
,
conditionIndex
)
=>
(
<
Card
<
Collapse
keepDOM
activeKey=
{
selectedConditionKeys
}
onChange=
{
(
activeKeys
)
=>
handleConditionCollapseChange
(
selectedOperation
.
id
,
activeKeys
,
)
}
>
{
conditions
.
map
(
(
condition
,
conditionIndex
)
=>
(
<
Collapse
.
Panel
key=
{
condition
.
id
}
bodyStyle=
{
{
padding
:
10
}
}
className=
'!rounded-lg'
itemKey=
{
condition
.
id
}
header=
{
<
Space
spacing=
{
8
}
>
<
Tag
size=
'small'
>
{
`C${conditionIndex + 1}`
}
</
Tag
>
<
Text
type=
'tertiary'
size=
'small'
>
{
condition
.
path
||
t
(
'未设置 path'
)
}
</
Text
>
</
Space
>
}
>
<
div
className=
'flex items-center justify-between mb-2'
>
<
Tag
size=
'small'
>
{
`C${conditionIndex + 1}`
}
</
Tag
>
<
div
>
<
div
className=
'flex justify-end mb-2'
>
<
Button
theme=
'borderless'
type=
'danger'
icon=
{
<
IconDelete
/>
}
size=
'small'
onClick=
{
()
=>
removeCondition
(
operation
.
id
,
condition
.
id
)
removeCondition
(
selectedOperation
.
id
,
condition
.
id
,
)
}
/>
</
div
>
<
Row
gutter=
{
12
}
>
<
Col
xs=
{
24
}
md=
{
10
}
>
<
Text
type=
'tertiary'
size=
'small'
>
<
Text
type=
'tertiary'
size=
'small'
>
path
</
Text
>
<
Input
...
...
@@ -1174,13 +1573,16 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
placeholder=
'model'
onChange=
{
(
nextValue
)
=>
updateCondition
(
o
peration
.
id
,
selectedO
peration
.
id
,
condition
.
id
,
{
path
:
nextValue
},
)
}
/>
<
Space
wrap
style=
{
{
marginTop
:
6
}
}
>
<
Space
wrap
style=
{
{
marginTop
:
6
}
}
>
{
CONDITION_PATH_SUGGESTIONS
.
map
(
(
pathItem
)
=>
(
<
Tag
...
...
@@ -1190,7 +1592,7 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
className=
'cursor-pointer'
onClick=
{
()
=>
updateCondition
(
o
peration
.
id
,
selectedO
peration
.
id
,
condition
.
id
,
{
path
:
pathItem
},
)
...
...
@@ -1203,15 +1605,20 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
</
Space
>
</
Col
>
<
Col
xs=
{
24
}
md=
{
8
}
>
<
Text
type=
'tertiary'
size=
'small'
>
<
Text
type=
'tertiary'
size=
'small'
>
mode
</
Text
>
<
Select
value=
{
condition
.
mode
}
optionList=
{
CONDITION_MODE_OPTIONS
}
optionList=
{
CONDITION_MODE_OPTIONS
}
onChange=
{
(
nextValue
)
=>
updateCondition
(
o
peration
.
id
,
selectedO
peration
.
id
,
condition
.
id
,
{
mode
:
nextValue
},
)
...
...
@@ -1220,7 +1627,10 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
/>
</
Col
>
<
Col
xs=
{
24
}
md=
{
6
}
>
<
Text
type=
'tertiary'
size=
'small'
>
<
Text
type=
'tertiary'
size=
'small'
>
value
</
Text
>
<
Input
...
...
@@ -1228,7 +1638,7 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
placeholder=
'gpt'
onChange=
{
(
nextValue
)
=>
updateCondition
(
o
peration
.
id
,
selectedO
peration
.
id
,
condition
.
id
,
{
value_text
:
nextValue
},
)
...
...
@@ -1238,12 +1648,14 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
</
Row
>
<
Space
style=
{
{
marginTop
:
8
}
}
>
<
Switch
checked=
{
condition
.
invert
}
checked=
{
Boolean
(
condition
.
invert
,
)
}
checkedText=
{
t
(
'开'
)
}
uncheckedText=
{
t
(
'关'
)
}
onChange=
{
(
nextValue
)
=>
updateCondition
(
o
peration
.
id
,
selectedO
peration
.
id
,
condition
.
id
,
{
invert
:
nextValue
},
)
...
...
@@ -1253,14 +1665,18 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
invert
</
Text
>
<
Switch
checked=
{
condition
.
pass_missing_key
}
checked=
{
Boolean
(
condition
.
pass_missing_key
,
)
}
checkedText=
{
t
(
'开'
)
}
uncheckedText=
{
t
(
'关'
)
}
onChange=
{
(
nextValue
)
=>
updateCondition
(
o
peration
.
id
,
selectedO
peration
.
id
,
condition
.
id
,
{
pass_missing_key
:
nextValue
},
{
pass_missing_key
:
nextValue
,
},
)
}
/>
...
...
@@ -1268,16 +1684,37 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
pass_missing_key
</
Text
>
</
Space
>
</
Card
>
))
}
</
Space
>
</
div
>
</
Collapse
.
Panel
>
),
)
}
</
Collapse
>
)
}
</
div
>
</
Card
>
);
})
}
</
Space
>
<
Card
className=
'!rounded-xl border mt-3'
>
})()
)
:
(
<
Card
className=
'!rounded-2xl !border-0'
bodyStyle=
{
{
padding
:
14
,
background
:
'var(--semi-color-fill-0)'
,
}
}
>
<
Text
type=
'tertiary'
>
{
t
(
'请选择一条规则进行编辑。'
)
}
</
Text
>
</
Card
>
)
}
<
Card
className=
'!rounded-2xl !border-0 mt-3'
bodyStyle=
{
{
padding
:
12
,
background
:
'var(--semi-color-fill-0)'
,
}
}
>
<
div
className=
'flex items-center justify-between mb-2'
>
<
Text
>
{
t
(
'实时 JSON 预览'
)
}
</
Text
>
<
Tag
color=
'grey'
>
{
t
(
'预览'
)
}
</
Tag
>
...
...
@@ -1286,6 +1723,8 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
{
visualPreview
||
'
{}
'
}
</
pre
>
</
Card
>
</
Col
>
</
Row
>
</
div
>
)
}
</
div
>
...
...
@@ -1295,7 +1734,7 @@ const ParamOverrideEditorModal = ({ visible, value, onSave, onCancel }) => {
<
Button
onClick=
{
formatJson
}
>
{
t
(
'格式化'
)
}
</
Button
>
<
Tag
color=
'grey'
>
{
t
(
'普通编辑'
)
}
</
Tag
>
</
Space
>
<
Input
.
TextArea
<
TextArea
value=
{
jsonText
}
autosize=
{
{
minRows
:
18
,
maxRows
:
28
}
}
onChange=
{
(
nextValue
)
=>
handleJsonChange
(
nextValue
??
''
)
}
...
...
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