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
a6f08a68
authored
Oct 02, 2025
by
CaIon
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/main'
parents
995ac442
bc657762
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
275 additions
and
169 deletions
+275
-169
web/jsconfig.json
+1
-2
web/src/components/common/modals/TwoFactorAuthModal.jsx
+3
-1
web/src/components/layout/Footer.jsx
+34
-23
web/src/components/layout/PageLayout.jsx
+13
-3
web/src/components/settings/SystemSetting.jsx
+51
-23
web/src/components/table/channels/modals/EditChannelModal.jsx
+8
-23
web/src/components/table/mj-logs/MjLogsFilters.jsx
+2
-2
web/src/components/table/task-logs/TaskLogsColumnDefs.jsx
+3
-2
web/src/components/table/task-logs/TaskLogsFilters.jsx
+2
-2
web/src/components/table/usage-logs/UsageLogsFilters.jsx
+2
-2
web/src/components/topup/RechargeCard.jsx
+57
-25
web/src/components/topup/index.jsx
+20
-11
web/src/components/topup/modals/PaymentConfirmModal.jsx
+4
-3
web/src/constants/console.constants.js
+5
-5
web/src/helpers/api.js
+0
-2
web/src/helpers/render.jsx
+1
-1
web/src/hooks/common/useSidebar.js
+4
-1
web/src/i18n/locales/en.json
+1
-2
web/src/pages/Setting/Operation/SettingsGeneral.jsx
+14
-13
web/src/pages/Setting/Operation/SettingsMonitoring.jsx
+2
-1
web/src/pages/Setting/Payment/SettingsPaymentGateway.jsx
+31
-11
web/src/pages/Setting/Ratio/ModelRatioSettings.jsx
+17
-11
No files found.
web/jsconfig.json
View file @
a6f08a68
...
@@ -6,4 +6,4 @@
...
@@ -6,4 +6,4 @@
}
}
},
},
"include"
:
[
"src/**/*"
]
"include"
:
[
"src/**/*"
]
}
}
\ No newline at end of file
web/src/components/common/modals/TwoFactorAuthModal.jsx
View file @
a6f08a68
...
@@ -135,7 +135,9 @@ const TwoFactorAuthModal = ({
...
@@ -135,7 +135,9 @@ const TwoFactorAuthModal = ({
autoFocus
autoFocus
/>
/>
<
Typography
.
Text
type=
'tertiary'
size=
'small'
className=
'mt-2 block'
>
<
Typography
.
Text
type=
'tertiary'
size=
'small'
className=
'mt-2 block'
>
{
t
(
'支持6位TOTP验证码或8位备用码,可到`个人设置-安全设置-两步验证设置`配置或查看。'
)
}
{
t
(
'支持6位TOTP验证码或8位备用码,可到`个人设置-安全设置-两步验证设置`配置或查看。'
,
)
}
</
Typography
.
Text
>
</
Typography
.
Text
>
</
div
>
</
div
>
</
div
>
</
div
>
...
...
web/src/components/layout/Footer.jsx
View file @
a6f08a68
...
@@ -143,14 +143,6 @@ const FooterBar = () => {
...
@@ -143,14 +143,6 @@ const FooterBar = () => {
Midjourney-Proxy
Midjourney-Proxy
</
a
>
</
a
>
<
a
<
a
href=
'https://github.com/Deeptrain-Community/chatnio'
target=
'_blank'
rel=
'noopener noreferrer'
className=
'!text-semi-color-text-1'
>
chatnio
</
a
>
<
a
href=
'https://github.com/Calcium-Ion/neko-api-key-tool'
href=
'https://github.com/Calcium-Ion/neko-api-key-tool'
target=
'_blank'
target=
'_blank'
rel=
'noopener noreferrer'
rel=
'noopener noreferrer'
...
@@ -163,7 +155,7 @@ const FooterBar = () => {
...
@@ -163,7 +155,7 @@ const FooterBar = () => {
<
div
className=
'text-left'
>
<
div
className=
'text-left'
>
<
p
className=
'!text-semi-color-text-0 font-semibold mb-5'
>
<
p
className=
'!text-semi-color-text-0 font-semibold mb-5'
>
{
t
(
'
基于New API的项目
'
)
}
{
t
(
'
友情链接
'
)
}
</
p
>
</
p
>
<
div
className=
'flex flex-col gap-4'
>
<
div
className=
'flex flex-col gap-4'
>
<
a
<
a
...
@@ -174,7 +166,22 @@ const FooterBar = () => {
...
@@ -174,7 +166,22 @@ const FooterBar = () => {
>
>
new-api-horizon
new-api-horizon
</
a
>
</
a
>
{
/* <a href="https://github.com/VoAPI/VoAPI" target="_blank" rel="noopener noreferrer" className="!text-semi-color-text-1">VoAPI</a> */
}
<
a
href=
'https://github.com/coaidev/coai'
target=
'_blank'
rel=
'noopener noreferrer'
className=
'!text-semi-color-text-1'
>
CoAI
</
a
>
<
a
href=
'https://www.gpt-load.com/'
target=
'_blank'
rel=
'noopener noreferrer'
className=
'!text-semi-color-text-1'
>
GPT-Load
</
a
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
...
@@ -200,15 +207,6 @@ const FooterBar = () => {
...
@@ -200,15 +207,6 @@ const FooterBar = () => {
>
>
New API
New API
</
a
>
</
a
>
<
span
className=
'!text-semi-color-text-1'
>
&
</
span
>
<
a
href=
'https://github.com/songquanpeng/one-api'
target=
'_blank'
rel=
'noopener noreferrer'
className=
'!text-semi-color-primary font-medium'
>
One API
</
a
>
</
div
>
</
div
>
</
div
>
</
div
>
</
footer
>
</
footer
>
...
@@ -223,10 +221,23 @@ const FooterBar = () => {
...
@@ -223,10 +221,23 @@ const FooterBar = () => {
return
(
return
(
<
div
className=
'w-full'
>
<
div
className=
'w-full'
>
{
footer
?
(
{
footer
?
(
<
div
<
div
className=
'relative'
>
className=
'custom-footer'
<
div
dangerouslySetInnerHTML=
{
{
__html
:
footer
}
}
className=
'custom-footer'
></
div
>
dangerouslySetInnerHTML=
{
{
__html
:
footer
}
}
></
div
>
<
div
className=
'absolute bottom-2 right-4 text-xs !text-semi-color-text-2 opacity-70'
>
<
span
>
{
t
(
'设计与开发由'
)
}
</
span
>
<
a
href=
'https://github.com/QuantumNous/new-api'
target=
'_blank'
rel=
'noopener noreferrer'
className=
'!text-semi-color-primary font-medium'
>
New API
</
a
>
</
div
>
</
div
>
)
:
(
)
:
(
customFooter
customFooter
)
}
)
}
...
...
web/src/components/layout/PageLayout.jsx
View file @
a6f08a68
...
@@ -48,9 +48,19 @@ const PageLayout = () => {
...
@@ -48,9 +48,19 @@ const PageLayout = () => {
const
{
i18n
}
=
useTranslation
();
const
{
i18n
}
=
useTranslation
();
const
location
=
useLocation
();
const
location
=
useLocation
();
const
shouldHideFooter
=
const
cardProPages
=
[
location
.
pathname
.
startsWith
(
'/console'
)
||
'/console/channel'
,
location
.
pathname
===
'/pricing'
;
'/console/log'
,
'/console/redemption'
,
'/console/user'
,
'/console/token'
,
'/console/midjourney'
,
'/console/task'
,
'/console/models'
,
'/pricing'
,
];
const
shouldHideFooter
=
cardProPages
.
includes
(
location
.
pathname
);
const
shouldInnerPadding
=
const
shouldInnerPadding
=
location
.
pathname
.
includes
(
'/console'
)
&&
location
.
pathname
.
includes
(
'/console'
)
&&
...
...
web/src/components/settings/SystemSetting.jsx
View file @
a6f08a68
...
@@ -46,7 +46,6 @@ import { useTranslation } from 'react-i18next';
...
@@ -46,7 +46,6 @@ import { useTranslation } from 'react-i18next';
const
SystemSetting
=
()
=>
{
const
SystemSetting
=
()
=>
{
const
{
t
}
=
useTranslation
();
const
{
t
}
=
useTranslation
();
let
[
inputs
,
setInputs
]
=
useState
({
let
[
inputs
,
setInputs
]
=
useState
({
PasswordLoginEnabled
:
''
,
PasswordLoginEnabled
:
''
,
PasswordRegisterEnabled
:
''
,
PasswordRegisterEnabled
:
''
,
EmailVerificationEnabled
:
''
,
EmailVerificationEnabled
:
''
,
...
@@ -212,7 +211,9 @@ const SystemSetting = () => {
...
@@ -212,7 +211,9 @@ const SystemSetting = () => {
setInputs
(
newInputs
);
setInputs
(
newInputs
);
setOriginInputs
(
newInputs
);
setOriginInputs
(
newInputs
);
// 同步模式布尔到本地状态
// 同步模式布尔到本地状态
if
(
typeof
newInputs
[
'fetch_setting.domain_filter_mode'
]
!==
'undefined'
)
{
if
(
typeof
newInputs
[
'fetch_setting.domain_filter_mode'
]
!==
'undefined'
)
{
setDomainFilterMode
(
!!
newInputs
[
'fetch_setting.domain_filter_mode'
]);
setDomainFilterMode
(
!!
newInputs
[
'fetch_setting.domain_filter_mode'
]);
}
}
if
(
typeof
newInputs
[
'fetch_setting.ip_filter_mode'
]
!==
'undefined'
)
{
if
(
typeof
newInputs
[
'fetch_setting.ip_filter_mode'
]
!==
'undefined'
)
{
...
@@ -749,14 +750,17 @@ const SystemSetting = () => {
...
@@ -749,14 +750,17 @@ const SystemSetting = () => {
noLabel
noLabel
extraText=
{
t
(
'SSRF防护开关详细说明'
)
}
extraText=
{
t
(
'SSRF防护开关详细说明'
)
}
onChange=
{
(
e
)
=>
onChange=
{
(
e
)
=>
handleCheckboxChange
(
'fetch_setting.enable_ssrf_protection'
,
e
)
handleCheckboxChange
(
'fetch_setting.enable_ssrf_protection'
,
e
,
)
}
}
>
>
{
t
(
'启用SSRF防护(推荐开启以保护服务器安全)'
)
}
{
t
(
'启用SSRF防护(推荐开启以保护服务器安全)'
)
}
</
Form
.
Checkbox
>
</
Form
.
Checkbox
>
</
Col
>
</
Col
>
</
Row
>
</
Row
>
<
Row
<
Row
gutter=
{
{
xs
:
8
,
sm
:
16
,
md
:
24
,
lg
:
24
,
xl
:
24
,
xxl
:
24
}
}
gutter=
{
{
xs
:
8
,
sm
:
16
,
md
:
24
,
lg
:
24
,
xl
:
24
,
xxl
:
24
}
}
style=
{
{
marginTop
:
16
}
}
style=
{
{
marginTop
:
16
}
}
...
@@ -767,14 +771,19 @@ const SystemSetting = () => {
...
@@ -767,14 +771,19 @@ const SystemSetting = () => {
noLabel
noLabel
extraText=
{
t
(
'私有IP访问详细说明'
)
}
extraText=
{
t
(
'私有IP访问详细说明'
)
}
onChange=
{
(
e
)
=>
onChange=
{
(
e
)
=>
handleCheckboxChange
(
'fetch_setting.allow_private_ip'
,
e
)
handleCheckboxChange
(
'fetch_setting.allow_private_ip'
,
e
,
)
}
}
>
>
{
t
(
'允许访问私有IP地址(127.0.0.1、192.168.x.x等内网地址)'
)
}
{
t
(
'允许访问私有IP地址(127.0.0.1、192.168.x.x等内网地址)'
,
)
}
</
Form
.
Checkbox
>
</
Form
.
Checkbox
>
</
Col
>
</
Col
>
</
Row
>
</
Row
>
<
Row
<
Row
gutter=
{
{
xs
:
8
,
sm
:
16
,
md
:
24
,
lg
:
24
,
xl
:
24
,
xxl
:
24
}
}
gutter=
{
{
xs
:
8
,
sm
:
16
,
md
:
24
,
lg
:
24
,
xl
:
24
,
xxl
:
24
}
}
style=
{
{
marginTop
:
16
}
}
style=
{
{
marginTop
:
16
}
}
...
@@ -785,7 +794,10 @@ const SystemSetting = () => {
...
@@ -785,7 +794,10 @@ const SystemSetting = () => {
noLabel
noLabel
extraText=
{
t
(
'域名IP过滤详细说明'
)
}
extraText=
{
t
(
'域名IP过滤详细说明'
)
}
onChange=
{
(
e
)
=>
onChange=
{
(
e
)
=>
handleCheckboxChange
(
'fetch_setting.apply_ip_filter_for_domain'
,
e
)
handleCheckboxChange
(
'fetch_setting.apply_ip_filter_for_domain'
,
e
,
)
}
}
style=
{
{
marginBottom
:
8
}
}
style=
{
{
marginBottom
:
8
}
}
>
>
...
@@ -794,17 +806,23 @@ const SystemSetting = () => {
...
@@ -794,17 +806,23 @@ const SystemSetting = () => {
<
Text
strong
>
<
Text
strong
>
{
t
(
domainFilterMode
?
'域名白名单'
:
'域名黑名单'
)
}
{
t
(
domainFilterMode
?
'域名白名单'
:
'域名黑名单'
)
}
</
Text
>
</
Text
>
<
Text
type=
"secondary"
style=
{
{
display
:
'block'
,
marginBottom
:
8
}
}
>
<
Text
{
t
(
'支持通配符格式,如:example.com, *.api.example.com'
)
}
type=
'secondary'
style=
{
{
display
:
'block'
,
marginBottom
:
8
}
}
>
{
t
(
'支持通配符格式,如:example.com, *.api.example.com'
,
)
}
</
Text
>
</
Text
>
<
Radio
.
Group
<
Radio
.
Group
type=
'button'
type=
'button'
value=
{
domainFilterMode
?
'whitelist'
:
'blacklist'
}
value=
{
domainFilterMode
?
'whitelist'
:
'blacklist'
}
onChange=
{
(
val
)
=>
{
onChange=
{
(
val
)
=>
{
const
selected
=
val
&&
val
.
target
?
val
.
target
.
value
:
val
;
const
selected
=
val
&&
val
.
target
?
val
.
target
.
value
:
val
;
const
isWhitelist
=
selected
===
'whitelist'
;
const
isWhitelist
=
selected
===
'whitelist'
;
setDomainFilterMode
(
isWhitelist
);
setDomainFilterMode
(
isWhitelist
);
setInputs
(
prev
=>
({
setInputs
(
(
prev
)
=>
({
...
prev
,
...
prev
,
'fetch_setting.domain_filter_mode'
:
isWhitelist
,
'fetch_setting.domain_filter_mode'
:
isWhitelist
,
}));
}));
...
@@ -819,9 +837,9 @@ const SystemSetting = () => {
...
@@ -819,9 +837,9 @@ const SystemSetting = () => {
onChange=
{
(
value
)
=>
{
onChange=
{
(
value
)
=>
{
setDomainList
(
value
);
setDomainList
(
value
);
// 触发Form的onChange事件
// 触发Form的onChange事件
setInputs
(
prev
=>
({
setInputs
(
(
prev
)
=>
({
...
prev
,
...
prev
,
'fetch_setting.domain_list'
:
value
'fetch_setting.domain_list'
:
value
,
}));
}));
}
}
}
}
placeholder=
{
t
(
'输入域名后回车,如:example.com'
)
}
placeholder=
{
t
(
'输入域名后回车,如:example.com'
)
}
...
@@ -838,17 +856,21 @@ const SystemSetting = () => {
...
@@ -838,17 +856,21 @@ const SystemSetting = () => {
<
Text
strong
>
<
Text
strong
>
{
t
(
ipFilterMode
?
'IP白名单'
:
'IP黑名单'
)
}
{
t
(
ipFilterMode
?
'IP白名单'
:
'IP黑名单'
)
}
</
Text
>
</
Text
>
<
Text
type=
"secondary"
style=
{
{
display
:
'block'
,
marginBottom
:
8
}
}
>
<
Text
type=
'secondary'
style=
{
{
display
:
'block'
,
marginBottom
:
8
}
}
>
{
t
(
'支持CIDR格式,如:8.8.8.8, 192.168.1.0/24'
)
}
{
t
(
'支持CIDR格式,如:8.8.8.8, 192.168.1.0/24'
)
}
</
Text
>
</
Text
>
<
Radio
.
Group
<
Radio
.
Group
type=
'button'
type=
'button'
value=
{
ipFilterMode
?
'whitelist'
:
'blacklist'
}
value=
{
ipFilterMode
?
'whitelist'
:
'blacklist'
}
onChange=
{
(
val
)
=>
{
onChange=
{
(
val
)
=>
{
const
selected
=
val
&&
val
.
target
?
val
.
target
.
value
:
val
;
const
selected
=
val
&&
val
.
target
?
val
.
target
.
value
:
val
;
const
isWhitelist
=
selected
===
'whitelist'
;
const
isWhitelist
=
selected
===
'whitelist'
;
setIpFilterMode
(
isWhitelist
);
setIpFilterMode
(
isWhitelist
);
setInputs
(
prev
=>
({
setInputs
(
(
prev
)
=>
({
...
prev
,
...
prev
,
'fetch_setting.ip_filter_mode'
:
isWhitelist
,
'fetch_setting.ip_filter_mode'
:
isWhitelist
,
}));
}));
...
@@ -863,9 +885,9 @@ const SystemSetting = () => {
...
@@ -863,9 +885,9 @@ const SystemSetting = () => {
onChange=
{
(
value
)
=>
{
onChange=
{
(
value
)
=>
{
setIpList
(
value
);
setIpList
(
value
);
// 触发Form的onChange事件
// 触发Form的onChange事件
setInputs
(
prev
=>
({
setInputs
(
(
prev
)
=>
({
...
prev
,
...
prev
,
'fetch_setting.ip_list'
:
value
'fetch_setting.ip_list'
:
value
,
}));
}));
}
}
}
}
placeholder=
{
t
(
'输入IP地址后回车,如:8.8.8.8'
)
}
placeholder=
{
t
(
'输入IP地址后回车,如:8.8.8.8'
)
}
...
@@ -880,7 +902,10 @@ const SystemSetting = () => {
...
@@ -880,7 +902,10 @@ const SystemSetting = () => {
>
>
<
Col
xs=
{
24
}
sm=
{
24
}
md=
{
24
}
lg=
{
24
}
xl=
{
24
}
>
<
Col
xs=
{
24
}
sm=
{
24
}
md=
{
24
}
lg=
{
24
}
xl=
{
24
}
>
<
Text
strong
>
{
t
(
'允许的端口'
)
}
</
Text
>
<
Text
strong
>
{
t
(
'允许的端口'
)
}
</
Text
>
<
Text
type=
"secondary"
style=
{
{
display
:
'block'
,
marginBottom
:
8
}
}
>
<
Text
type=
'secondary'
style=
{
{
display
:
'block'
,
marginBottom
:
8
}
}
>
{
t
(
'支持单个端口和端口范围,如:80, 443, 8000-8999'
)
}
{
t
(
'支持单个端口和端口范围,如:80, 443, 8000-8999'
)
}
</
Text
>
</
Text
>
<
TagInput
<
TagInput
...
@@ -888,15 +913,18 @@ const SystemSetting = () => {
...
@@ -888,15 +913,18 @@ const SystemSetting = () => {
onChange=
{
(
value
)
=>
{
onChange=
{
(
value
)
=>
{
setAllowedPorts
(
value
);
setAllowedPorts
(
value
);
// 触发Form的onChange事件
// 触发Form的onChange事件
setInputs
(
prev
=>
({
setInputs
(
(
prev
)
=>
({
...
prev
,
...
prev
,
'fetch_setting.allowed_ports'
:
value
'fetch_setting.allowed_ports'
:
value
,
}));
}));
}
}
}
}
placeholder=
{
t
(
'输入端口后回车,如:80 或 8000-8999'
)
}
placeholder=
{
t
(
'输入端口后回车,如:80 或 8000-8999'
)
}
style=
{
{
width
:
'100%'
}
}
style=
{
{
width
:
'100%'
}
}
/>
/>
<
Text
type=
"secondary"
style=
{
{
display
:
'block'
,
marginBottom
:
8
}
}
>
<
Text
type=
'secondary'
style=
{
{
display
:
'block'
,
marginBottom
:
8
}
}
>
{
t
(
'端口配置详细说明'
)
}
{
t
(
'端口配置详细说明'
)
}
</
Text
>
</
Text
>
</
Col
>
</
Col
>
...
...
web/src/components/table/channels/modals/EditChannelModal.jsx
View file @
a6f08a68
...
@@ -91,22 +91,7 @@ const REGION_EXAMPLE = {
...
@@ -91,22 +91,7 @@ const REGION_EXAMPLE = {
// 支持并且已适配通过接口获取模型列表的渠道类型
// 支持并且已适配通过接口获取模型列表的渠道类型
const
MODEL_FETCHABLE_TYPES
=
new
Set
([
const
MODEL_FETCHABLE_TYPES
=
new
Set
([
1
,
1
,
4
,
14
,
34
,
17
,
26
,
24
,
47
,
25
,
20
,
23
,
31
,
35
,
40
,
42
,
48
,
4
,
14
,
34
,
17
,
26
,
24
,
47
,
25
,
20
,
23
,
31
,
35
,
40
,
42
,
48
,
43
,
43
,
]);
]);
...
@@ -279,8 +264,8 @@ const EditChannelModal = (props) => {
...
@@ -279,8 +264,8 @@ const EditChannelModal = (props) => {
const
scrollToSection
=
(
sectionKey
)
=>
{
const
scrollToSection
=
(
sectionKey
)
=>
{
const
sectionElement
=
formSectionRefs
.
current
[
sectionKey
];
const
sectionElement
=
formSectionRefs
.
current
[
sectionKey
];
if
(
sectionElement
)
{
if
(
sectionElement
)
{
sectionElement
.
scrollIntoView
({
sectionElement
.
scrollIntoView
({
behavior
:
'smooth'
,
behavior
:
'smooth'
,
block
:
'start'
,
block
:
'start'
,
inline
:
'nearest'
inline
:
'nearest'
});
});
...
@@ -301,7 +286,7 @@ const EditChannelModal = (props) => {
...
@@ -301,7 +286,7 @@ const EditChannelModal = (props) => {
}
else
{
}
else
{
newIndex
=
currentSectionIndex
<
availableSections
.
length
-
1
?
currentSectionIndex
+
1
:
0
;
newIndex
=
currentSectionIndex
<
availableSections
.
length
-
1
?
currentSectionIndex
+
1
:
0
;
}
}
setCurrentSectionIndex
(
newIndex
);
setCurrentSectionIndex
(
newIndex
);
scrollToSection
(
availableSections
[
newIndex
]);
scrollToSection
(
availableSections
[
newIndex
]);
};
};
...
@@ -1340,7 +1325,7 @@ const EditChannelModal = (props) => {
...
@@ -1340,7 +1325,7 @@ const EditChannelModal = (props) => {
type=
'tertiary'
type=
'tertiary'
icon=
{
<
IconChevronUp
/>
}
icon=
{
<
IconChevronUp
/>
}
onClick=
{
()
=>
navigateToSection
(
'up'
)
}
onClick=
{
()
=>
navigateToSection
(
'up'
)
}
style=
{
{
style=
{
{
borderRadius
:
'50%'
,
borderRadius
:
'50%'
,
width
:
'32px'
,
width
:
'32px'
,
height
:
'32px'
,
height
:
'32px'
,
...
@@ -1356,7 +1341,7 @@ const EditChannelModal = (props) => {
...
@@ -1356,7 +1341,7 @@ const EditChannelModal = (props) => {
type=
'tertiary'
type=
'tertiary'
icon=
{
<
IconChevronDown
/>
}
icon=
{
<
IconChevronDown
/>
}
onClick=
{
()
=>
navigateToSection
(
'down'
)
}
onClick=
{
()
=>
navigateToSection
(
'down'
)
}
style=
{
{
style=
{
{
borderRadius
:
'50%'
,
borderRadius
:
'50%'
,
width
:
'32px'
,
width
:
'32px'
,
height
:
'32px'
,
height
:
'32px'
,
...
@@ -1398,8 +1383,8 @@ const EditChannelModal = (props) => {
...
@@ -1398,8 +1383,8 @@ const EditChannelModal = (props) => {
>
>
{
()
=>
(
{
()
=>
(
<
Spin
spinning=
{
loading
}
>
<
Spin
spinning=
{
loading
}
>
<
div
<
div
className=
'p-2'
className=
'p-2'
ref=
{
formContainerRef
}
ref=
{
formContainerRef
}
>
>
<
div
ref=
{
el
=>
formSectionRefs
.
current
.
basicInfo
=
el
}
>
<
div
ref=
{
el
=>
formSectionRefs
.
current
.
basicInfo
=
el
}
>
...
...
web/src/components/table/mj-logs/MjLogsFilters.jsx
View file @
a6f08a68
...
@@ -56,10 +56,10 @@ const MjLogsFilters = ({
...
@@ -56,10 +56,10 @@ const MjLogsFilters = ({
showClear
showClear
pure
pure
size=
'small'
size=
'small'
presets=
{
DATE_RANGE_PRESETS
.
map
(
preset
=>
({
presets=
{
DATE_RANGE_PRESETS
.
map
(
(
preset
)
=>
({
text
:
t
(
preset
.
text
),
text
:
t
(
preset
.
text
),
start
:
preset
.
start
(),
start
:
preset
.
start
(),
end
:
preset
.
end
()
end
:
preset
.
end
()
,
}))
}
}))
}
/>
/>
</
div
>
</
div
>
...
...
web/src/components/table/task-logs/TaskLogsColumnDefs.jsx
View file @
a6f08a68
...
@@ -36,8 +36,9 @@ import {
...
@@ -36,8 +36,9 @@ import {
}
from
'lucide-react'
;
}
from
'lucide-react'
;
import
{
import
{
TASK_ACTION_FIRST_TAIL_GENERATE
,
TASK_ACTION_FIRST_TAIL_GENERATE
,
TASK_ACTION_GENERATE
,
TASK_ACTION_REFERENCE_GENERATE
,
TASK_ACTION_GENERATE
,
TASK_ACTION_TEXT_GENERATE
TASK_ACTION_REFERENCE_GENERATE
,
TASK_ACTION_TEXT_GENERATE
,
}
from
'../../../constants/common.constant'
;
}
from
'../../../constants/common.constant'
;
import
{
CHANNEL_OPTIONS
}
from
'../../../constants/channel.constants'
;
import
{
CHANNEL_OPTIONS
}
from
'../../../constants/channel.constants'
;
...
...
web/src/components/table/task-logs/TaskLogsFilters.jsx
View file @
a6f08a68
...
@@ -56,10 +56,10 @@ const TaskLogsFilters = ({
...
@@ -56,10 +56,10 @@ const TaskLogsFilters = ({
showClear
showClear
pure
pure
size=
'small'
size=
'small'
presets=
{
DATE_RANGE_PRESETS
.
map
(
preset
=>
({
presets=
{
DATE_RANGE_PRESETS
.
map
(
(
preset
)
=>
({
text
:
t
(
preset
.
text
),
text
:
t
(
preset
.
text
),
start
:
preset
.
start
(),
start
:
preset
.
start
(),
end
:
preset
.
end
()
end
:
preset
.
end
()
,
}))
}
}))
}
/>
/>
</
div
>
</
div
>
...
...
web/src/components/table/usage-logs/UsageLogsFilters.jsx
View file @
a6f08a68
...
@@ -57,10 +57,10 @@ const LogsFilters = ({
...
@@ -57,10 +57,10 @@ const LogsFilters = ({
showClear
showClear
pure
pure
size=
'small'
size=
'small'
presets=
{
DATE_RANGE_PRESETS
.
map
(
preset
=>
({
presets=
{
DATE_RANGE_PRESETS
.
map
(
(
preset
)
=>
({
text
:
t
(
preset
.
text
),
text
:
t
(
preset
.
text
),
start
:
preset
.
start
(),
start
:
preset
.
start
(),
end
:
preset
.
end
()
end
:
preset
.
end
()
,
}))
}
}))
}
/>
/>
</
div
>
</
div
>
...
...
web/src/components/topup/RechargeCard.jsx
View file @
a6f08a68
...
@@ -30,7 +30,8 @@ import {
...
@@ -30,7 +30,8 @@ import {
Space
,
Space
,
Row
,
Row
,
Col
,
Col
,
Spin
,
Tooltip
Spin
,
Tooltip
,
}
from
'@douyinfe/semi-ui'
;
}
from
'@douyinfe/semi-ui'
;
import
{
SiAlipay
,
SiWechat
,
SiStripe
}
from
'react-icons/si'
;
import
{
SiAlipay
,
SiWechat
,
SiStripe
}
from
'react-icons/si'
;
import
{
CreditCard
,
Coins
,
Wallet
,
BarChart2
,
TrendingUp
}
from
'lucide-react'
;
import
{
CreditCard
,
Coins
,
Wallet
,
BarChart2
,
TrendingUp
}
from
'lucide-react'
;
...
@@ -266,7 +267,8 @@ const RechargeCard = ({
...
@@ -266,7 +267,8 @@ const RechargeCard = ({
{
payMethods
&&
payMethods
.
length
>
0
?
(
{
payMethods
&&
payMethods
.
length
>
0
?
(
<
Space
wrap
>
<
Space
wrap
>
{
payMethods
.
map
((
payMethod
)
=>
{
{
payMethods
.
map
((
payMethod
)
=>
{
const
minTopupVal
=
Number
(
payMethod
.
min_topup
)
||
0
;
const
minTopupVal
=
Number
(
payMethod
.
min_topup
)
||
0
;
const
isStripe
=
payMethod
.
type
===
'stripe'
;
const
isStripe
=
payMethod
.
type
===
'stripe'
;
const
disabled
=
const
disabled
=
(
!
enableOnlineTopUp
&&
!
isStripe
)
||
(
!
enableOnlineTopUp
&&
!
isStripe
)
||
...
@@ -280,7 +282,9 @@ const RechargeCard = ({
...
@@ -280,7 +282,9 @@ const RechargeCard = ({
type=
'tertiary'
type=
'tertiary'
onClick=
{
()
=>
preTopUp
(
payMethod
.
type
)
}
onClick=
{
()
=>
preTopUp
(
payMethod
.
type
)
}
disabled=
{
disabled
}
disabled=
{
disabled
}
loading=
{
paymentLoading
&&
payWay
===
payMethod
.
type
}
loading=
{
paymentLoading
&&
payWay
===
payMethod
.
type
}
icon=
{
icon=
{
payMethod
.
type
===
'alipay'
?
(
payMethod
.
type
===
'alipay'
?
(
<
SiAlipay
size=
{
18
}
color=
'#1677FF'
/>
<
SiAlipay
size=
{
18
}
color=
'#1677FF'
/>
...
@@ -291,7 +295,10 @@ const RechargeCard = ({
...
@@ -291,7 +295,10 @@ const RechargeCard = ({
)
:
(
)
:
(
<
CreditCard
<
CreditCard
size=
{
18
}
size=
{
18
}
color=
{
payMethod
.
color
||
'var(--semi-color-text-2)'
}
color=
{
payMethod
.
color
||
'var(--semi-color-text-2)'
}
/>
/>
)
)
}
}
...
@@ -301,12 +308,22 @@ const RechargeCard = ({
...
@@ -301,12 +308,22 @@ const RechargeCard = ({
</
Button
>
</
Button
>
);
);
return
disabled
&&
minTopupVal
>
Number
(
topUpCount
||
0
)
?
(
return
disabled
&&
<
Tooltip
content=
{
t
(
'此支付方式最低充值金额为'
)
+
' '
+
minTopupVal
}
key=
{
payMethod
.
type
}
>
minTopupVal
>
Number
(
topUpCount
||
0
)
?
(
<
Tooltip
content=
{
t
(
'此支付方式最低充值金额为'
)
+
' '
+
minTopupVal
}
key=
{
payMethod
.
type
}
>
{
buttonEl
}
{
buttonEl
}
</
Tooltip
>
</
Tooltip
>
)
:
(
)
:
(
<
React
.
Fragment
key=
{
payMethod
.
type
}
>
{
buttonEl
}
</
React
.
Fragment
>
<
React
.
Fragment
key=
{
payMethod
.
type
}
>
{
buttonEl
}
</
React
.
Fragment
>
);
);
})
}
})
}
</
Space
>
</
Space
>
...
@@ -324,23 +341,27 @@ const RechargeCard = ({
...
@@ -324,23 +341,27 @@ const RechargeCard = ({
<
Form
.
Slot
label=
{
t
(
'选择充值额度'
)
}
>
<
Form
.
Slot
label=
{
t
(
'选择充值额度'
)
}
>
<
div
className=
'grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2'
>
<
div
className=
'grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2'
>
{
presetAmounts
.
map
((
preset
,
index
)
=>
{
{
presetAmounts
.
map
((
preset
,
index
)
=>
{
const
discount
=
preset
.
discount
||
topupInfo
?.
discount
?.[
preset
.
value
]
||
1.0
;
const
discount
=
preset
.
discount
||
topupInfo
?.
discount
?.[
preset
.
value
]
||
1.0
;
const
originalPrice
=
preset
.
value
*
priceRatio
;
const
originalPrice
=
preset
.
value
*
priceRatio
;
const
discountedPrice
=
originalPrice
*
discount
;
const
discountedPrice
=
originalPrice
*
discount
;
const
hasDiscount
=
discount
<
1.0
;
const
hasDiscount
=
discount
<
1.0
;
const
actualPay
=
discountedPrice
;
const
actualPay
=
discountedPrice
;
const
save
=
originalPrice
-
discountedPrice
;
const
save
=
originalPrice
-
discountedPrice
;
return
(
return
(
<
Card
<
Card
key=
{
index
}
key=
{
index
}
style=
{
{
style=
{
{
cursor
:
'pointer'
,
cursor
:
'pointer'
,
border
:
selectedPreset
===
preset
.
value
border
:
?
'2px solid var(--semi-color-primary)'
selectedPreset
===
preset
.
value
:
'1px solid var(--semi-color-border)'
,
?
'2px solid var(--semi-color-primary)'
:
'1px solid var(--semi-color-border)'
,
height
:
'100%'
,
height
:
'100%'
,
width
:
'100%'
width
:
'100%'
,
}
}
}
}
bodyStyle=
{
{
padding
:
'12px'
}
}
bodyStyle=
{
{
padding
:
'12px'
}
}
onClick=
{
()
=>
{
onClick=
{
()
=>
{
...
@@ -352,24 +373,35 @@ const RechargeCard = ({
...
@@ -352,24 +373,35 @@ const RechargeCard = ({
}
}
}
}
>
>
<
div
style=
{
{
textAlign
:
'center'
}
}
>
<
div
style=
{
{
textAlign
:
'center'
}
}
>
<
Typography
.
Title
heading=
{
6
}
style=
{
{
margin
:
'0 0 8px 0'
}
}
>
<
Typography
.
Title
heading=
{
6
}
style=
{
{
margin
:
'0 0 8px 0'
}
}
>
<
Coins
size=
{
18
}
/>
<
Coins
size=
{
18
}
/>
{
formatLargeNumber
(
preset
.
value
)
}
{
formatLargeNumber
(
preset
.
value
)
}
{
hasDiscount
&&
(
{
hasDiscount
&&
(
<
Tag
style=
{
{
marginLeft
:
4
}
}
color=
"green"
>
<
Tag
style=
{
{
marginLeft
:
4
}
}
color=
'green'
>
{
t
(
'折'
).
includes
(
'off'
)
?
{
t
(
'折'
).
includes
(
'off'
)
((
1
-
parseFloat
(
discount
))
*
100
).
toFixed
(
1
)
:
?
(
(
discount
*
10
).
toFixed
(
1
)
}{
t
(
'折'
)
}
(
1
-
parseFloat
(
discount
))
*
</
Tag
>
100
).
toFixed
(
1
)
:
(
discount
*
10
).
toFixed
(
1
)
}
{
t
(
'折'
)
}
</
Tag
>
)
}
)
}
</
Typography
.
Title
>
</
Typography
.
Title
>
<
div
style=
{
{
<
div
color
:
'var(--semi-color-text-2)'
,
style=
{
{
fontSize
:
'12px'
,
color
:
'var(--semi-color-text-2)'
,
margin
:
'4px 0'
fontSize
:
'12px'
,
}
}
>
margin
:
'4px 0'
,
}
}
>
{
t
(
'实付'
)
}
{
actualPay
.
toFixed
(
2
)
}
,
{
t
(
'实付'
)
}
{
actualPay
.
toFixed
(
2
)
}
,
{
hasDiscount
?
`${t('节省')} ${save.toFixed(2)}`
:
`${t('节省')} 0.00`
}
{
hasDiscount
?
`${t('节省')} ${save.toFixed(2)}`
:
`${t('节省')} 0.00`
}
</
div
>
</
div
>
</
div
>
</
div
>
</
Card
>
</
Card
>
...
...
web/src/components/topup/index.jsx
View file @
a6f08a68
...
@@ -80,11 +80,11 @@ const TopUp = () => {
...
@@ -80,11 +80,11 @@ const TopUp = () => {
// 预设充值额度选项
// 预设充值额度选项
const
[
presetAmounts
,
setPresetAmounts
]
=
useState
([]);
const
[
presetAmounts
,
setPresetAmounts
]
=
useState
([]);
const
[
selectedPreset
,
setSelectedPreset
]
=
useState
(
null
);
const
[
selectedPreset
,
setSelectedPreset
]
=
useState
(
null
);
// 充值配置信息
// 充值配置信息
const
[
topupInfo
,
setTopupInfo
]
=
useState
({
const
[
topupInfo
,
setTopupInfo
]
=
useState
({
amount_options
:
[],
amount_options
:
[],
discount
:
{}
discount
:
{}
,
});
});
const
topUp
=
async
()
=>
{
const
topUp
=
async
()
=>
{
...
@@ -262,9 +262,9 @@ const TopUp = () => {
...
@@ -262,9 +262,9 @@ const TopUp = () => {
if
(
success
)
{
if
(
success
)
{
setTopupInfo
({
setTopupInfo
({
amount_options
:
data
.
amount_options
||
[],
amount_options
:
data
.
amount_options
||
[],
discount
:
data
.
discount
||
{}
discount
:
data
.
discount
||
{}
,
});
});
// 处理支付方式
// 处理支付方式
let
payMethods
=
data
.
pay_methods
||
[];
let
payMethods
=
data
.
pay_methods
||
[];
try
{
try
{
...
@@ -280,10 +280,15 @@ const TopUp = () => {
...
@@ -280,10 +280,15 @@ const TopUp = () => {
payMethods
=
payMethods
.
map
((
method
)
=>
{
payMethods
=
payMethods
.
map
((
method
)
=>
{
// 规范化最小充值数
// 规范化最小充值数
const
normalizedMinTopup
=
Number
(
method
.
min_topup
);
const
normalizedMinTopup
=
Number
(
method
.
min_topup
);
method
.
min_topup
=
Number
.
isFinite
(
normalizedMinTopup
)
?
normalizedMinTopup
:
0
;
method
.
min_topup
=
Number
.
isFinite
(
normalizedMinTopup
)
?
normalizedMinTopup
:
0
;
// Stripe 的最小充值从后端字段回填
// Stripe 的最小充值从后端字段回填
if
(
method
.
type
===
'stripe'
&&
(
!
method
.
min_topup
||
method
.
min_topup
<=
0
))
{
if
(
method
.
type
===
'stripe'
&&
(
!
method
.
min_topup
||
method
.
min_topup
<=
0
)
)
{
const
stripeMin
=
Number
(
data
.
stripe_min_topup
);
const
stripeMin
=
Number
(
data
.
stripe_min_topup
);
if
(
Number
.
isFinite
(
stripeMin
))
{
if
(
Number
.
isFinite
(
stripeMin
))
{
method
.
min_topup
=
stripeMin
;
method
.
min_topup
=
stripeMin
;
...
@@ -313,7 +318,11 @@ const TopUp = () => {
...
@@ -313,7 +318,11 @@ const TopUp = () => {
setPayMethods
(
payMethods
);
setPayMethods
(
payMethods
);
const
enableStripeTopUp
=
data
.
enable_stripe_topup
||
false
;
const
enableStripeTopUp
=
data
.
enable_stripe_topup
||
false
;
const
enableOnlineTopUp
=
data
.
enable_online_topup
||
false
;
const
enableOnlineTopUp
=
data
.
enable_online_topup
||
false
;
const
minTopUpValue
=
enableOnlineTopUp
?
data
.
min_topup
:
enableStripeTopUp
?
data
.
stripe_min_topup
:
1
;
const
minTopUpValue
=
enableOnlineTopUp
?
data
.
min_topup
:
enableStripeTopUp
?
data
.
stripe_min_topup
:
1
;
setEnableOnlineTopUp
(
enableOnlineTopUp
);
setEnableOnlineTopUp
(
enableOnlineTopUp
);
setEnableStripeTopUp
(
enableStripeTopUp
);
setEnableStripeTopUp
(
enableStripeTopUp
);
setMinTopUp
(
minTopUpValue
);
setMinTopUp
(
minTopUpValue
);
...
@@ -330,12 +339,12 @@ const TopUp = () => {
...
@@ -330,12 +339,12 @@ const TopUp = () => {
console
.
log
(
'解析支付方式失败:'
,
e
);
console
.
log
(
'解析支付方式失败:'
,
e
);
setPayMethods
([]);
setPayMethods
([]);
}
}
// 如果有自定义充值数量选项,使用它们替换默认的预设选项
// 如果有自定义充值数量选项,使用它们替换默认的预设选项
if
(
data
.
amount_options
&&
data
.
amount_options
.
length
>
0
)
{
if
(
data
.
amount_options
&&
data
.
amount_options
.
length
>
0
)
{
const
customPresets
=
data
.
amount_options
.
map
(
amount
=>
({
const
customPresets
=
data
.
amount_options
.
map
(
(
amount
)
=>
({
value
:
amount
,
value
:
amount
,
discount
:
data
.
discount
[
amount
]
||
1.0
discount
:
data
.
discount
[
amount
]
||
1.0
,
}));
}));
setPresetAmounts
(
customPresets
);
setPresetAmounts
(
customPresets
);
}
}
...
@@ -483,7 +492,7 @@ const TopUp = () => {
...
@@ -483,7 +492,7 @@ const TopUp = () => {
const
selectPresetAmount
=
(
preset
)
=>
{
const
selectPresetAmount
=
(
preset
)
=>
{
setTopUpCount
(
preset
.
value
);
setTopUpCount
(
preset
.
value
);
setSelectedPreset
(
preset
.
value
);
setSelectedPreset
(
preset
.
value
);
// 计算实际支付金额,考虑折扣
// 计算实际支付金额,考虑折扣
const
discount
=
preset
.
discount
||
topupInfo
.
discount
[
preset
.
value
]
||
1.0
;
const
discount
=
preset
.
discount
||
topupInfo
.
discount
[
preset
.
value
]
||
1.0
;
const
discountedAmount
=
preset
.
value
*
priceRatio
*
discount
;
const
discountedAmount
=
preset
.
value
*
priceRatio
*
discount
;
...
...
web/src/components/topup/modals/PaymentConfirmModal.jsx
View file @
a6f08a68
...
@@ -40,9 +40,10 @@ const PaymentConfirmModal = ({
...
@@ -40,9 +40,10 @@ const PaymentConfirmModal = ({
amountNumber
,
amountNumber
,
discountRate
,
discountRate
,
})
=>
{
})
=>
{
const
hasDiscount
=
discountRate
&&
discountRate
>
0
&&
discountRate
<
1
&&
amountNumber
>
0
;
const
hasDiscount
=
const
originalAmount
=
hasDiscount
?
(
amountNumber
/
discountRate
)
:
0
;
discountRate
&&
discountRate
>
0
&&
discountRate
<
1
&&
amountNumber
>
0
;
const
discountAmount
=
hasDiscount
?
(
originalAmount
-
amountNumber
)
:
0
;
const
originalAmount
=
hasDiscount
?
amountNumber
/
discountRate
:
0
;
const
discountAmount
=
hasDiscount
?
originalAmount
-
amountNumber
:
0
;
return
(
return
(
<
Modal
<
Modal
title=
{
title=
{
...
...
web/src/constants/console.constants.js
View file @
a6f08a68
...
@@ -24,26 +24,26 @@ export const DATE_RANGE_PRESETS = [
...
@@ -24,26 +24,26 @@ export const DATE_RANGE_PRESETS = [
{
{
text
:
'今天'
,
text
:
'今天'
,
start
:
()
=>
dayjs
().
startOf
(
'day'
).
toDate
(),
start
:
()
=>
dayjs
().
startOf
(
'day'
).
toDate
(),
end
:
()
=>
dayjs
().
endOf
(
'day'
).
toDate
()
end
:
()
=>
dayjs
().
endOf
(
'day'
).
toDate
()
,
},
},
{
{
text
:
'近 7 天'
,
text
:
'近 7 天'
,
start
:
()
=>
dayjs
().
subtract
(
6
,
'day'
).
startOf
(
'day'
).
toDate
(),
start
:
()
=>
dayjs
().
subtract
(
6
,
'day'
).
startOf
(
'day'
).
toDate
(),
end
:
()
=>
dayjs
().
endOf
(
'day'
).
toDate
()
end
:
()
=>
dayjs
().
endOf
(
'day'
).
toDate
()
,
},
},
{
{
text
:
'本周'
,
text
:
'本周'
,
start
:
()
=>
dayjs
().
startOf
(
'week'
).
toDate
(),
start
:
()
=>
dayjs
().
startOf
(
'week'
).
toDate
(),
end
:
()
=>
dayjs
().
endOf
(
'week'
).
toDate
()
end
:
()
=>
dayjs
().
endOf
(
'week'
).
toDate
()
,
},
},
{
{
text
:
'近 30 天'
,
text
:
'近 30 天'
,
start
:
()
=>
dayjs
().
subtract
(
29
,
'day'
).
startOf
(
'day'
).
toDate
(),
start
:
()
=>
dayjs
().
subtract
(
29
,
'day'
).
startOf
(
'day'
).
toDate
(),
end
:
()
=>
dayjs
().
endOf
(
'day'
).
toDate
()
end
:
()
=>
dayjs
().
endOf
(
'day'
).
toDate
()
,
},
},
{
{
text
:
'本月'
,
text
:
'本月'
,
start
:
()
=>
dayjs
().
startOf
(
'month'
).
toDate
(),
start
:
()
=>
dayjs
().
startOf
(
'month'
).
toDate
(),
end
:
()
=>
dayjs
().
endOf
(
'month'
).
toDate
()
end
:
()
=>
dayjs
().
endOf
(
'month'
).
toDate
()
,
},
},
];
];
web/src/helpers/api.js
View file @
a6f08a68
...
@@ -131,13 +131,11 @@ export const buildApiPayload = (
...
@@ -131,13 +131,11 @@ export const buildApiPayload = (
seed
:
'seed'
,
seed
:
'seed'
,
};
};
Object
.
entries
(
parameterMappings
).
forEach
(([
key
,
param
])
=>
{
Object
.
entries
(
parameterMappings
).
forEach
(([
key
,
param
])
=>
{
const
enabled
=
parameterEnabled
[
key
];
const
enabled
=
parameterEnabled
[
key
];
const
value
=
inputs
[
param
];
const
value
=
inputs
[
param
];
const
hasValue
=
value
!==
undefined
&&
value
!==
null
;
const
hasValue
=
value
!==
undefined
&&
value
!==
null
;
if
(
enabled
&&
hasValue
)
{
if
(
enabled
&&
hasValue
)
{
payload
[
param
]
=
value
;
payload
[
param
]
=
value
;
}
}
...
...
web/src/helpers/render.jsx
View file @
a6f08a68
...
@@ -1074,7 +1074,7 @@ export function renderModelPrice(
...
@@ -1074,7 +1074,7 @@ export function renderModelPrice(
(
completionTokens
/
1000000
)
*
completionRatioPrice
*
groupRatio
+
(
completionTokens
/
1000000
)
*
completionRatioPrice
*
groupRatio
+
(
webSearchCallCount
/
1000
)
*
webSearchPrice
*
groupRatio
+
(
webSearchCallCount
/
1000
)
*
webSearchPrice
*
groupRatio
+
(
fileSearchCallCount
/
1000
)
*
fileSearchPrice
*
groupRatio
+
(
fileSearchCallCount
/
1000
)
*
fileSearchPrice
*
groupRatio
+
(
imageGenerationCallPrice
*
groupRatio
)
;
imageGenerationCallPrice
*
groupRatio
;
return
(
return
(
<>
<>
...
...
web/src/hooks/common/useSidebar.js
View file @
a6f08a68
...
@@ -183,7 +183,10 @@ export const useSidebar = () => {
...
@@ -183,7 +183,10 @@ export const useSidebar = () => {
sidebarEventTarget
.
addEventListener
(
SIDEBAR_REFRESH_EVENT
,
handleRefresh
);
sidebarEventTarget
.
addEventListener
(
SIDEBAR_REFRESH_EVENT
,
handleRefresh
);
return
()
=>
{
return
()
=>
{
sidebarEventTarget
.
removeEventListener
(
SIDEBAR_REFRESH_EVENT
,
handleRefresh
);
sidebarEventTarget
.
removeEventListener
(
SIDEBAR_REFRESH_EVENT
,
handleRefresh
,
);
};
};
},
[
adminConfig
]);
},
[
adminConfig
]);
...
...
web/src/i18n/locales/en.json
View file @
a6f08a68
...
@@ -759,7 +759,6 @@
...
@@ -759,7 +759,6 @@
"获取当前设置失败"
:
"Failed to get current settings"
,
"获取当前设置失败"
:
"Failed to get current settings"
,
"设置已更新"
:
"Settings updated"
,
"设置已更新"
:
"Settings updated"
,
"更新设置失败"
:
"Update settings failed"
,
"更新设置失败"
:
"Update settings failed"
,
"确认解绑"
:
"Confirm unbinding"
,
"您确定要解绑WxPusher吗?"
:
"Are you sure you want to unbind WxPusher?"
,
"您确定要解绑WxPusher吗?"
:
"Are you sure you want to unbind WxPusher?"
,
"解绑失败"
:
"Unbinding failed"
,
"解绑失败"
:
"Unbinding failed"
,
"订阅事件"
:
"Subscribe to events"
,
"订阅事件"
:
"Subscribe to events"
,
...
@@ -1478,7 +1477,7 @@
...
@@ -1478,7 +1477,7 @@
"相关项目"
:
"Related Projects"
,
"相关项目"
:
"Related Projects"
,
"基于New API的项目"
:
"Projects Based on New API"
,
"基于New API的项目"
:
"Projects Based on New API"
,
"版权所有"
:
"All rights reserved"
,
"版权所有"
:
"All rights reserved"
,
"设计与开发由"
:
"Designed & Developed
with love
by"
,
"设计与开发由"
:
"Designed & Developed by"
,
"演示站点"
:
"Demo Site"
,
"演示站点"
:
"Demo Site"
,
"页面未找到,请检查您的浏览器地址是否正确"
:
"Page not found, please check if your browser address is correct"
,
"页面未找到,请检查您的浏览器地址是否正确"
:
"Page not found, please check if your browser address is correct"
,
"您无权访问此页面,请联系管理员"
:
"You do not have permission to access this page. Please contact the administrator."
,
"您无权访问此页面,请联系管理员"
:
"You do not have permission to access this page. Please contact the administrator."
,
...
...
web/src/pages/Setting/Operation/SettingsGeneral.jsx
View file @
a6f08a68
...
@@ -130,19 +130,20 @@ export default function GeneralSettings(props) {
...
@@ -130,19 +130,20 @@ export default function GeneralSettings(props) {
showClear
showClear
/>
/>
</
Col
>
</
Col
>
{
inputs
.
QuotaPerUnit
!==
'500000'
&&
inputs
.
QuotaPerUnit
!==
500000
&&
(
{
inputs
.
QuotaPerUnit
!==
'500000'
&&
<
Col
xs=
{
24
}
sm=
{
12
}
md=
{
8
}
lg=
{
8
}
xl=
{
8
}
>
inputs
.
QuotaPerUnit
!==
500000
&&
(
<
Form
.
Input
<
Col
xs=
{
24
}
sm=
{
12
}
md=
{
8
}
lg=
{
8
}
xl=
{
8
}
>
field=
{
'QuotaPerUnit'
}
<
Form
.
Input
label=
{
t
(
'单位美元额度'
)
}
field=
{
'QuotaPerUnit'
}
initValue=
{
''
}
label=
{
t
(
'单位美元额度'
)
}
placeholder=
{
t
(
'一单位货币能兑换的额度'
)
}
initValue=
{
''
}
onChange=
{
handleFieldChange
(
'QuotaPerUnit'
)
}
placeholder=
{
t
(
'一单位货币能兑换的额度'
)
}
showClear
onChange=
{
handleFieldChange
(
'QuotaPerUnit'
)
}
onClick=
{
()
=>
setShowQuotaWarning
(
true
)
}
showClear
/>
onClick=
{
()
=>
setShowQuotaWarning
(
true
)
}
</
Col
>
/>
)
}
</
Col
>
)
}
<
Col
xs=
{
24
}
sm=
{
12
}
md=
{
8
}
lg=
{
8
}
xl=
{
8
}
>
<
Col
xs=
{
24
}
sm=
{
12
}
md=
{
8
}
lg=
{
8
}
xl=
{
8
}
>
<
Form
.
Input
<
Form
.
Input
field=
{
'USDExchangeRate'
}
field=
{
'USDExchangeRate'
}
...
...
web/src/pages/Setting/Operation/SettingsMonitoring.jsx
View file @
a6f08a68
...
@@ -128,7 +128,8 @@ export default function SettingsMonitoring(props) {
...
@@ -128,7 +128,8 @@ export default function SettingsMonitoring(props) {
onChange=
{
(
value
)
=>
onChange=
{
(
value
)
=>
setInputs
({
setInputs
({
...
inputs
,
...
inputs
,
'monitor_setting.auto_test_channel_minutes'
:
parseInt
(
value
),
'monitor_setting.auto_test_channel_minutes'
:
parseInt
(
value
),
})
})
}
}
/>
/>
...
...
web/src/pages/Setting/Payment/SettingsPaymentGateway.jsx
View file @
a6f08a68
...
@@ -118,14 +118,20 @@ export default function SettingsPaymentGateway(props) {
...
@@ -118,14 +118,20 @@ export default function SettingsPaymentGateway(props) {
}
}
}
}
if
(
originInputs
[
'AmountOptions'
]
!==
inputs
.
AmountOptions
&&
inputs
.
AmountOptions
.
trim
()
!==
''
)
{
if
(
originInputs
[
'AmountOptions'
]
!==
inputs
.
AmountOptions
&&
inputs
.
AmountOptions
.
trim
()
!==
''
)
{
if
(
!
verifyJSON
(
inputs
.
AmountOptions
))
{
if
(
!
verifyJSON
(
inputs
.
AmountOptions
))
{
showError
(
t
(
'自定义充值数量选项不是合法的 JSON 数组'
));
showError
(
t
(
'自定义充值数量选项不是合法的 JSON 数组'
));
return
;
return
;
}
}
}
}
if
(
originInputs
[
'AmountDiscount'
]
!==
inputs
.
AmountDiscount
&&
inputs
.
AmountDiscount
.
trim
()
!==
''
)
{
if
(
originInputs
[
'AmountDiscount'
]
!==
inputs
.
AmountDiscount
&&
inputs
.
AmountDiscount
.
trim
()
!==
''
)
{
if
(
!
verifyJSON
(
inputs
.
AmountDiscount
))
{
if
(
!
verifyJSON
(
inputs
.
AmountDiscount
))
{
showError
(
t
(
'充值金额折扣配置不是合法的 JSON 对象'
));
showError
(
t
(
'充值金额折扣配置不是合法的 JSON 对象'
));
return
;
return
;
...
@@ -163,10 +169,16 @@ export default function SettingsPaymentGateway(props) {
...
@@ -163,10 +169,16 @@ export default function SettingsPaymentGateway(props) {
options
.
push
({
key
:
'PayMethods'
,
value
:
inputs
.
PayMethods
});
options
.
push
({
key
:
'PayMethods'
,
value
:
inputs
.
PayMethods
});
}
}
if
(
originInputs
[
'AmountOptions'
]
!==
inputs
.
AmountOptions
)
{
if
(
originInputs
[
'AmountOptions'
]
!==
inputs
.
AmountOptions
)
{
options
.
push
({
key
:
'payment_setting.amount_options'
,
value
:
inputs
.
AmountOptions
});
options
.
push
({
key
:
'payment_setting.amount_options'
,
value
:
inputs
.
AmountOptions
,
});
}
}
if
(
originInputs
[
'AmountDiscount'
]
!==
inputs
.
AmountDiscount
)
{
if
(
originInputs
[
'AmountDiscount'
]
!==
inputs
.
AmountDiscount
)
{
options
.
push
({
key
:
'payment_setting.amount_discount'
,
value
:
inputs
.
AmountDiscount
});
options
.
push
({
key
:
'payment_setting.amount_discount'
,
value
:
inputs
.
AmountDiscount
,
});
}
}
// 发送请求
// 发送请求
...
@@ -273,7 +285,7 @@ export default function SettingsPaymentGateway(props) {
...
@@ -273,7 +285,7 @@ export default function SettingsPaymentGateway(props) {
placeholder=
{
t
(
'为一个 JSON 文本'
)
}
placeholder=
{
t
(
'为一个 JSON 文本'
)
}
autosize
autosize
/>
/>
<
Row
<
Row
gutter=
{
{
xs
:
8
,
sm
:
16
,
md
:
24
,
lg
:
24
,
xl
:
24
,
xxl
:
24
}
}
gutter=
{
{
xs
:
8
,
sm
:
16
,
md
:
24
,
lg
:
24
,
xl
:
24
,
xxl
:
24
}
}
style=
{
{
marginTop
:
16
}
}
style=
{
{
marginTop
:
16
}
}
...
@@ -282,13 +294,17 @@ export default function SettingsPaymentGateway(props) {
...
@@ -282,13 +294,17 @@ export default function SettingsPaymentGateway(props) {
<
Form
.
TextArea
<
Form
.
TextArea
field=
'AmountOptions'
field=
'AmountOptions'
label=
{
t
(
'自定义充值数量选项'
)
}
label=
{
t
(
'自定义充值数量选项'
)
}
placeholder=
{
t
(
'为一个 JSON 数组,例如:[10, 20, 50, 100, 200, 500]'
)
}
placeholder=
{
t
(
'为一个 JSON 数组,例如:[10, 20, 50, 100, 200, 500]'
,
)
}
autosize
autosize
extraText=
{
t
(
'设置用户可选择的充值数量选项,例如:[10, 20, 50, 100, 200, 500]'
)
}
extraText=
{
t
(
'设置用户可选择的充值数量选项,例如:[10, 20, 50, 100, 200, 500]'
,
)
}
/>
/>
</
Col
>
</
Col
>
</
Row
>
</
Row
>
<
Row
<
Row
gutter=
{
{
xs
:
8
,
sm
:
16
,
md
:
24
,
lg
:
24
,
xl
:
24
,
xxl
:
24
}
}
gutter=
{
{
xs
:
8
,
sm
:
16
,
md
:
24
,
lg
:
24
,
xl
:
24
,
xxl
:
24
}
}
style=
{
{
marginTop
:
16
}
}
style=
{
{
marginTop
:
16
}
}
...
@@ -297,13 +313,17 @@ export default function SettingsPaymentGateway(props) {
...
@@ -297,13 +313,17 @@ export default function SettingsPaymentGateway(props) {
<
Form
.
TextArea
<
Form
.
TextArea
field=
'AmountDiscount'
field=
'AmountDiscount'
label=
{
t
(
'充值金额折扣配置'
)
}
label=
{
t
(
'充值金额折扣配置'
)
}
placeholder=
{
t
(
'为一个
JSON
对象,例如:
{
"100"
:
0.95
,
"200"
:
0.9
,
"500"
:
0.85
}
'
)
}
placeholder=
{
t
(
'为一个
JSON
对象,例如:
{
"100"
:
0.95
,
"200"
:
0.9
,
"500"
:
0.85
}
'
,
)
}
autosize
autosize
extraText=
{
t
(
'设置不同充值金额对应的折扣,键为充值金额,值为折扣率,例如:
{
"100"
:
0.95
,
"200"
:
0.9
,
"500"
:
0.85
}
'
)
}
extraText=
{
t
(
'设置不同充值金额对应的折扣,键为充值金额,值为折扣率,例如:
{
"100"
:
0.95
,
"200"
:
0.9
,
"500"
:
0.85
}
'
,
)
}
/>
/>
</
Col
>
</
Col
>
</
Row
>
</
Row
>
<
Button
onClick=
{
submitPayAddress
}
>
{
t
(
'更新支付设置'
)
}
</
Button
>
<
Button
onClick=
{
submitPayAddress
}
>
{
t
(
'更新支付设置'
)
}
</
Button
>
</
Form
.
Section
>
</
Form
.
Section
>
</
Form
>
</
Form
>
...
...
web/src/pages/Setting/Ratio/ModelRatioSettings.jsx
View file @
a6f08a68
...
@@ -226,8 +226,12 @@ export default function ModelRatioSettings(props) {
...
@@ -226,8 +226,12 @@ export default function ModelRatioSettings(props) {
<
Col
xs=
{
24
}
sm=
{
16
}
>
<
Col
xs=
{
24
}
sm=
{
16
}
>
<
Form
.
TextArea
<
Form
.
TextArea
label=
{
t
(
'图片输入倍率(仅部分模型支持该计费)'
)
}
label=
{
t
(
'图片输入倍率(仅部分模型支持该计费)'
)
}
extraText=
{
t
(
'图片输入相关的倍率设置,键为模型名称,值为倍率,仅部分模型支持该计费'
)
}
extraText=
{
t
(
placeholder=
{
t
(
'为一个
JSON
文本,键为模型名称,值为倍率,例如:
{
"gpt-image-1"
:
2
}
'
)
}
'图片输入相关的倍率设置,键为模型名称,值为倍率,仅部分模型支持该计费'
,
)
}
placeholder=
{
t
(
'为一个
JSON
文本,键为模型名称,值为倍率,例如:
{
"gpt-image-1"
:
2
}
'
,
)
}
field=
{
'ImageRatio'
}
field=
{
'ImageRatio'
}
autosize=
{
{
minRows
:
6
,
maxRows
:
12
}
}
autosize=
{
{
minRows
:
6
,
maxRows
:
12
}
}
trigger=
'blur'
trigger=
'blur'
...
@@ -238,9 +242,7 @@ export default function ModelRatioSettings(props) {
...
@@ -238,9 +242,7 @@ export default function ModelRatioSettings(props) {
message
:
'不是合法的 JSON 字符串'
,
message
:
'不是合法的 JSON 字符串'
,
},
},
]
}
]
}
onChange=
{
(
value
)
=>
onChange=
{
(
value
)
=>
setInputs
({
...
inputs
,
ImageRatio
:
value
})
}
setInputs
({
...
inputs
,
ImageRatio
:
value
})
}
/>
/>
</
Col
>
</
Col
>
</
Row
>
</
Row
>
...
@@ -249,7 +251,9 @@ export default function ModelRatioSettings(props) {
...
@@ -249,7 +251,9 @@ export default function ModelRatioSettings(props) {
<
Form
.
TextArea
<
Form
.
TextArea
label=
{
t
(
'音频倍率(仅部分模型支持该计费)'
)
}
label=
{
t
(
'音频倍率(仅部分模型支持该计费)'
)
}
extraText=
{
t
(
'音频输入相关的倍率设置,键为模型名称,值为倍率'
)
}
extraText=
{
t
(
'音频输入相关的倍率设置,键为模型名称,值为倍率'
)
}
placeholder=
{
t
(
'为一个
JSON
文本,键为模型名称,值为倍率,例如:
{
"gpt-4o-audio-preview"
:
16
}
'
)
}
placeholder=
{
t
(
'为一个
JSON
文本,键为模型名称,值为倍率,例如:
{
"gpt-4o-audio-preview"
:
16
}
'
,
)
}
field=
{
'AudioRatio'
}
field=
{
'AudioRatio'
}
autosize=
{
{
minRows
:
6
,
maxRows
:
12
}
}
autosize=
{
{
minRows
:
6
,
maxRows
:
12
}
}
trigger=
'blur'
trigger=
'blur'
...
@@ -260,9 +264,7 @@ export default function ModelRatioSettings(props) {
...
@@ -260,9 +264,7 @@ export default function ModelRatioSettings(props) {
message
:
'不是合法的 JSON 字符串'
,
message
:
'不是合法的 JSON 字符串'
,
},
},
]
}
]
}
onChange=
{
(
value
)
=>
onChange=
{
(
value
)
=>
setInputs
({
...
inputs
,
AudioRatio
:
value
})
}
setInputs
({
...
inputs
,
AudioRatio
:
value
})
}
/>
/>
</
Col
>
</
Col
>
</
Row
>
</
Row
>
...
@@ -270,8 +272,12 @@ export default function ModelRatioSettings(props) {
...
@@ -270,8 +272,12 @@ export default function ModelRatioSettings(props) {
<
Col
xs=
{
24
}
sm=
{
16
}
>
<
Col
xs=
{
24
}
sm=
{
16
}
>
<
Form
.
TextArea
<
Form
.
TextArea
label=
{
t
(
'音频补全倍率(仅部分模型支持该计费)'
)
}
label=
{
t
(
'音频补全倍率(仅部分模型支持该计费)'
)
}
extraText=
{
t
(
'音频输出补全相关的倍率设置,键为模型名称,值为倍率'
)
}
extraText=
{
t
(
placeholder=
{
t
(
'为一个
JSON
文本,键为模型名称,值为倍率,例如:
{
"gpt-4o-realtime"
:
2
}
'
)
}
'音频输出补全相关的倍率设置,键为模型名称,值为倍率'
,
)
}
placeholder=
{
t
(
'为一个
JSON
文本,键为模型名称,值为倍率,例如:
{
"gpt-4o-realtime"
:
2
}
'
,
)
}
field=
{
'AudioCompletionRatio'
}
field=
{
'AudioCompletionRatio'
}
autosize=
{
{
minRows
:
6
,
maxRows
:
12
}
}
autosize=
{
{
minRows
:
6
,
maxRows
:
12
}
}
trigger=
'blur'
trigger=
'blur'
...
...
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