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
f73ecc57
authored
Sep 09, 2023
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
移除不必要的功能
parent
e25bcce4
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
935 additions
and
1006 deletions
+935
-1006
common/constants.go
+4
-4
controller/midjourney.go
+66
-72
controller/misc.go
+4
-3
controller/relay-mj.go
+1
-0
controller/relay-text.go
+0
-6
controller/topup.go
+35
-60
middleware/distributor.go
+11
-41
model/midjourney.go
+1
-0
model/option.go
+12
-11
web/src/components/PersonalSetting.js
+155
-233
web/src/components/SystemSetting.js
+574
-517
web/src/pages/Home/index.js
+56
-43
web/src/pages/TopUp/index.js
+16
-16
No files found.
common/constants.go
View file @
f73ecc57
...
@@ -13,6 +13,10 @@ var StartTime = time.Now().Unix() // unit: second
...
@@ -13,6 +13,10 @@ var StartTime = time.Now().Unix() // unit: second
var
Version
=
"v0.0.0"
// this hard coding will be replaced automatically when building, no need to manually change
var
Version
=
"v0.0.0"
// this hard coding will be replaced automatically when building, no need to manually change
var
SystemName
=
"One API"
var
SystemName
=
"One API"
var
ServerAddress
=
"http://localhost:3000"
var
ServerAddress
=
"http://localhost:3000"
var
PayAddress
=
""
var
EpayId
=
""
var
EpayKey
=
""
var
Price
=
7
var
Footer
=
""
var
Footer
=
""
var
Logo
=
""
var
Logo
=
""
var
TopUpLink
=
""
var
TopUpLink
=
""
...
@@ -94,10 +98,6 @@ var RequestInterval = time.Duration(requestInterval) * time.Second
...
@@ -94,10 +98,6 @@ var RequestInterval = time.Duration(requestInterval) * time.Second
var
SyncFrequency
=
10
*
60
// unit is second, will be overwritten by SYNC_FREQUENCY
var
SyncFrequency
=
10
*
60
// unit is second, will be overwritten by SYNC_FREQUENCY
var
NormalPrice
=
1.5
var
StablePrice
=
6.0
var
BasePrice
=
1.5
const
(
const
(
RoleGuestUser
=
0
RoleGuestUser
=
0
RoleCommonUser
=
1
RoleCommonUser
=
1
...
...
controller/midjourney.go
View file @
f73ecc57
...
@@ -19,90 +19,84 @@ func UpdateMidjourneyTask() {
...
@@ -19,90 +19,84 @@ func UpdateMidjourneyTask() {
for
{
for
{
defer
func
()
{
defer
func
()
{
if
err
:=
recover
();
err
!=
nil
{
if
err
:=
recover
();
err
!=
nil
{
log
.
Printf
(
"UpdateMidjourneyTask: %v"
,
err
)
log
.
Printf
(
"UpdateMidjourneyTask
panic
: %v"
,
err
)
}
}
}()
}()
time
.
Sleep
(
time
.
Duration
(
15
)
*
time
.
Second
)
time
.
Sleep
(
time
.
Duration
(
15
)
*
time
.
Second
)
tasks
:=
model
.
GetAllUnFinishTasks
()
tasks
:=
model
.
GetAllUnFinishTasks
()
if
len
(
tasks
)
!=
0
{
if
len
(
tasks
)
!=
0
{
//log.Printf("UpdateMidjourneyTask: %v", time.Now())
ids
:=
make
([]
string
,
0
)
for
_
,
task
:=
range
tasks
{
for
_
,
task
:=
range
tasks
{
ids
=
append
(
ids
,
task
.
MjId
)
midjourneyChannel
,
err
:=
model
.
GetChannelById
(
task
.
ChannelId
,
true
)
}
if
err
!=
nil
{
requestUrl
:=
"http://107.173.171.147:8080/mj/task/list-by-condition"
log
.
Printf
(
"UpdateMidjourneyTask: %v"
,
err
)
requestBody
:=
map
[
string
]
interface
{}{
task
.
FailReason
=
fmt
.
Sprintf
(
"获取渠道信息失败,请联系管理员,渠道ID:%d"
,
task
.
ChannelId
)
"ids"
:
ids
,
task
.
Status
=
"FAILURE"
}
task
.
Progress
=
"100%"
jsonStr
,
err
:=
json
.
Marshal
(
requestBody
)
err
:=
task
.
Update
()
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"UpdateMidjourneyTask: %v"
,
err
)
log
.
Printf
(
"UpdateMidjourneyTask error: %v"
,
err
)
continue
}
}
continue
req
,
err
:=
http
.
NewRequest
(
"POST"
,
requestUrl
,
bytes
.
NewBuffer
(
jsonStr
))
if
err
!=
nil
{
log
.
Printf
(
"UpdateMidjourneyTask: %v"
,
err
)
continue
}
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
req
.
Header
.
Set
(
"mj-api-secret"
,
"uhiftyuwadbkjshbiklahcuitguasguzhxliawodawdu"
)
resp
,
err
:=
httpClient
.
Do
(
req
)
if
err
!=
nil
{
log
.
Printf
(
"UpdateMidjourneyTask: %v"
,
err
)
continue
}
defer
resp
.
Body
.
Close
()
var
response
[]
Midjourney
err
=
json
.
NewDecoder
(
resp
.
Body
)
.
Decode
(
&
response
)
if
err
!=
nil
{
log
.
Printf
(
"UpdateMidjourneyTask: %v"
,
err
)
continue
}
for
_
,
responseItem
:=
range
response
{
var
midjourneyTask
*
model
.
Midjourney
for
_
,
mj
:=
range
tasks
{
mj
.
MjId
=
responseItem
.
MjId
midjourneyTask
=
model
.
GetMjByuId
(
mj
.
Id
)
}
}
if
midjourneyTask
!=
nil
{
requestUrl
:=
fmt
.
Sprintf
(
"%s/mj/task/%s/fetch"
,
midjourneyChannel
.
BaseURL
,
task
.
MjId
)
midjourneyTask
.
Code
=
1
midjourneyTask
.
Progress
=
responseItem
.
Progress
req
,
err
:=
http
.
NewRequest
(
"GET"
,
requestUrl
,
bytes
.
NewBuffer
([]
byte
(
""
)))
midjourneyTask
.
PromptEn
=
responseItem
.
PromptEn
if
err
!=
nil
{
midjourneyTask
.
State
=
responseItem
.
State
log
.
Printf
(
"UpdateMidjourneyTask error: %v"
,
err
)
midjourneyTask
.
SubmitTime
=
responseItem
.
SubmitTime
continue
midjourneyTask
.
StartTime
=
responseItem
.
StartTime
}
midjourneyTask
.
FinishTime
=
responseItem
.
FinishTime
midjourneyTask
.
ImageUrl
=
responseItem
.
ImageUrl
req
.
Header
.
Set
(
"Content-Type"
,
"application/json"
)
midjourneyTask
.
Status
=
responseItem
.
Status
req
.
Header
.
Set
(
"mj-api-secret"
,
midjourneyChannel
.
Key
)
midjourneyTask
.
FailReason
=
responseItem
.
FailReason
resp
,
err
:=
httpClient
.
Do
(
req
)
if
midjourneyTask
.
Progress
!=
"100%"
&&
responseItem
.
FailReason
!=
""
{
if
err
!=
nil
{
log
.
Println
(
midjourneyTask
.
MjId
+
" 构建失败,"
+
midjourneyTask
.
FailReason
)
log
.
Printf
(
"UpdateMidjourneyTask error: %v"
,
err
)
midjourneyTask
.
Progress
=
"100%"
continue
err
=
model
.
CacheUpdateUserQuota
(
midjourneyTask
.
UserId
)
}
if
err
!=
nil
{
defer
resp
.
Body
.
Close
()
log
.
Println
(
"error update user quota cache: "
+
err
.
Error
())
var
responseItem
Midjourney
}
else
{
err
=
json
.
NewDecoder
(
resp
.
Body
)
.
Decode
(
&
responseItem
)
modelRatio
:=
common
.
GetModelRatio
(
imageModel
)
if
err
!=
nil
{
groupRatio
:=
common
.
GetGroupRatio
(
"default"
)
log
.
Printf
(
"UpdateMidjourneyTask error: %v"
,
err
)
ratio
:=
modelRatio
*
groupRatio
continue
quota
:=
int
(
ratio
*
1
*
1000
)
}
if
quota
!=
0
{
task
.
Code
=
1
err
:=
model
.
IncreaseUserQuota
(
midjourneyTask
.
UserId
,
quota
)
task
.
Progress
=
responseItem
.
Progress
if
err
!=
nil
{
task
.
PromptEn
=
responseItem
.
PromptEn
log
.
Println
(
"fail to increase user quota"
)
task
.
State
=
responseItem
.
State
}
task
.
SubmitTime
=
responseItem
.
SubmitTime
logContent
:=
fmt
.
Sprintf
(
"%s 构图失败,补偿 %s"
,
midjourneyTask
.
MjId
,
common
.
LogQuota
(
quota
))
task
.
StartTime
=
responseItem
.
StartTime
model
.
RecordLog
(
midjourneyTask
.
UserId
,
1
,
logContent
)
task
.
FinishTime
=
responseItem
.
FinishTime
task
.
ImageUrl
=
responseItem
.
ImageUrl
task
.
Status
=
responseItem
.
Status
task
.
FailReason
=
responseItem
.
FailReason
if
task
.
Progress
!=
"100%"
&&
responseItem
.
FailReason
!=
""
{
log
.
Println
(
task
.
MjId
+
" 构建失败,"
+
task
.
FailReason
)
task
.
Progress
=
"100%"
err
=
model
.
CacheUpdateUserQuota
(
task
.
UserId
)
if
err
!=
nil
{
log
.
Println
(
"error update user quota cache: "
+
err
.
Error
())
}
else
{
modelRatio
:=
common
.
GetModelRatio
(
imageModel
)
groupRatio
:=
common
.
GetGroupRatio
(
"default"
)
ratio
:=
modelRatio
*
groupRatio
quota
:=
int
(
ratio
*
1
*
1000
)
if
quota
!=
0
{
err
:=
model
.
IncreaseUserQuota
(
task
.
UserId
,
quota
)
if
err
!=
nil
{
log
.
Println
(
"fail to increase user quota"
)
}
}
logContent
:=
fmt
.
Sprintf
(
"%s 构图失败,补偿 %s"
,
task
.
MjId
,
common
.
LogQuota
(
quota
))
model
.
RecordLog
(
task
.
UserId
,
1
,
logContent
)
}
}
}
}
}
err
=
midjourneyTask
.
Update
()
err
=
task
.
Update
()
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Printf
(
"UpdateMidjourneyTaskFail: %v"
,
err
)
log
.
Printf
(
"UpdateMidjourneyTask error: %v"
,
err
)
}
log
.
Printf
(
"UpdateMidjourneyTask: %v"
,
midjourneyTask
)
}
}
log
.
Printf
(
"UpdateMidjourneyTask success: %v"
,
task
)
}
}
}
}
}
}
...
...
controller/misc.go
View file @
f73ecc57
...
@@ -27,15 +27,16 @@ func GetStatus(c *gin.Context) {
...
@@ -27,15 +27,16 @@ func GetStatus(c *gin.Context) {
"wechat_qrcode"
:
common
.
WeChatAccountQRCodeImageURL
,
"wechat_qrcode"
:
common
.
WeChatAccountQRCodeImageURL
,
"wechat_login"
:
common
.
WeChatAuthEnabled
,
"wechat_login"
:
common
.
WeChatAuthEnabled
,
"server_address"
:
common
.
ServerAddress
,
"server_address"
:
common
.
ServerAddress
,
"pay_address"
:
common
.
PayAddress
,
"epay_id"
:
common
.
EpayId
,
"epay_key"
:
common
.
EpayKey
,
"price"
:
common
.
Price
,
"turnstile_check"
:
common
.
TurnstileCheckEnabled
,
"turnstile_check"
:
common
.
TurnstileCheckEnabled
,
"turnstile_site_key"
:
common
.
TurnstileSiteKey
,
"turnstile_site_key"
:
common
.
TurnstileSiteKey
,
"top_up_link"
:
common
.
TopUpLink
,
"top_up_link"
:
common
.
TopUpLink
,
"chat_link"
:
common
.
ChatLink
,
"chat_link"
:
common
.
ChatLink
,
"quota_per_unit"
:
common
.
QuotaPerUnit
,
"quota_per_unit"
:
common
.
QuotaPerUnit
,
"display_in_currency"
:
common
.
DisplayInCurrencyEnabled
,
"display_in_currency"
:
common
.
DisplayInCurrencyEnabled
,
"normal_price"
:
common
.
NormalPrice
,
"stable_price"
:
common
.
StablePrice
,
"base_price"
:
common
.
BasePrice
,
},
},
})
})
return
return
...
...
controller/relay-mj.go
View file @
f73ecc57
...
@@ -356,6 +356,7 @@ func relayMidjourneySubmit(c *gin.Context, relayMode int) *MidjourneyResponse {
...
@@ -356,6 +356,7 @@ func relayMidjourneySubmit(c *gin.Context, relayMode int) *MidjourneyResponse {
Status
:
""
,
Status
:
""
,
Progress
:
"0%"
,
Progress
:
"0%"
,
FailReason
:
""
,
FailReason
:
""
,
ChannelId
:
c
.
GetInt
(
"channel_id"
),
}
}
if
midjResponse
.
Code
==
4
||
midjResponse
.
Code
==
24
{
if
midjResponse
.
Code
==
4
||
midjResponse
.
Code
==
24
{
midjourneyTask
.
FailReason
=
midjResponse
.
Description
midjourneyTask
.
FailReason
=
midjResponse
.
Description
...
...
controller/relay-text.go
View file @
f73ecc57
...
@@ -105,7 +105,6 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -105,7 +105,6 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
case
common
.
ChannelTypeXunfei
:
case
common
.
ChannelTypeXunfei
:
apiType
=
APITypeXunfei
apiType
=
APITypeXunfei
}
}
isStable
:=
c
.
GetBool
(
"stable"
)
baseURL
:=
common
.
ChannelBaseURLs
[
channelType
]
baseURL
:=
common
.
ChannelBaseURLs
[
channelType
]
requestURL
:=
c
.
Request
.
URL
.
String
()
requestURL
:=
c
.
Request
.
URL
.
String
()
...
@@ -189,15 +188,10 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
...
@@ -189,15 +188,10 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
preConsumedTokens
=
promptTokens
+
textRequest
.
MaxTokens
preConsumedTokens
=
promptTokens
+
textRequest
.
MaxTokens
}
}
modelRatio
:=
common
.
GetModelRatio
(
textRequest
.
Model
)
modelRatio
:=
common
.
GetModelRatio
(
textRequest
.
Model
)
stableRatio
:=
modelRatio
groupRatio
:=
common
.
GetGroupRatio
(
group
)
groupRatio
:=
common
.
GetGroupRatio
(
group
)
ratio
:=
modelRatio
*
groupRatio
ratio
:=
modelRatio
*
groupRatio
preConsumedQuota
:=
int
(
float64
(
preConsumedTokens
)
*
ratio
)
preConsumedQuota
:=
int
(
float64
(
preConsumedTokens
)
*
ratio
)
userQuota
,
err
:=
model
.
CacheGetUserQuota
(
userId
)
userQuota
,
err
:=
model
.
CacheGetUserQuota
(
userId
)
if
isStable
{
stableRatio
=
(
common
.
StablePrice
/
common
.
BasePrice
)
*
modelRatio
ratio
=
stableRatio
*
groupRatio
}
if
err
!=
nil
{
if
err
!=
nil
{
return
errorWrapper
(
err
,
"get_user_quota_failed"
,
http
.
StatusInternalServerError
)
return
errorWrapper
(
err
,
"get_user_quota_failed"
,
http
.
StatusInternalServerError
)
}
}
...
...
controller/topup.go
View file @
f73ecc57
...
@@ -24,31 +24,23 @@ type AmountRequest struct {
...
@@ -24,31 +24,23 @@ type AmountRequest struct {
TopUpCode
string
`json:"top_up_code"`
TopUpCode
string
`json:"top_up_code"`
}
}
//var client, _ = epay.NewClientWithUrl(&epay.Config{
func
GetEpayClient
()
*
epay
.
Client
{
// PartnerID: "1096",
if
common
.
PayAddress
==
""
||
common
.
EpayId
==
""
||
common
.
EpayKey
==
""
{
// Key: "n08V9LpE8JffA3NPP893689u8p39NV9J",
return
nil
//}, "https://api.lempay.org")
}
withUrl
,
err
:=
epay
.
NewClientWithUrl
(
&
epay
.
Config
{
var
client
,
_
=
epay
.
NewClientWithUrl
(
&
epay
.
Config
{
PartnerID
:
common
.
EpayId
,
PartnerID
:
"1064"
,
Key
:
common
.
EpayKey
,
Key
:
"nqrrZ5RjR86mKP8rKkyrOY5Pg8NmYfKR"
,
},
common
.
PayAddress
)
},
"https://pay.yunjuw.cn"
)
if
err
!=
nil
{
return
nil
func
GetAmount
(
id
int
,
count
float64
,
topUpCode
string
)
float64
{
amount
:=
count
*
1.5
if
topUpCode
!=
""
{
if
topUpCode
==
"nekoapi"
{
if
id
==
89
{
amount
=
count
*
0.8
}
else
if
id
==
105
||
id
==
107
{
amount
=
count
*
1.2
}
else
if
id
==
1
{
amount
=
count
*
1
}
else
if
id
==
98
{
amount
=
count
*
1.1
}
}
}
}
return
withUrl
}
func
GetAmount
(
count
float64
)
float64
{
// 别问为什么用float64,问就是这么点钱没必要
amount
:=
count
*
float64
(
common
.
Price
)
return
amount
return
amount
}
}
...
@@ -60,38 +52,24 @@ func RequestEpay(c *gin.Context) {
...
@@ -60,38 +52,24 @@ func RequestEpay(c *gin.Context) {
return
return
}
}
id
:=
c
.
GetInt
(
"id"
)
id
:=
c
.
GetInt
(
"id"
)
amount
:=
GetAmount
(
id
,
float64
(
req
.
Amount
),
req
.
TopUpCode
)
amount
:=
GetAmount
(
float64
(
req
.
Amount
))
if
id
!=
1
{
if
req
.
Amount
<
10
{
c
.
JSON
(
200
,
gin
.
H
{
"message"
:
"最小充值10元"
,
"data"
:
amount
,
"count"
:
10
})
return
}
}
if
req
.
PaymentMethod
==
"zfb"
{
if
req
.
PaymentMethod
==
"zfb"
{
if
amount
>
2000
{
c
.
JSON
(
200
,
gin
.
H
{
"message"
:
"支付宝最大充值2000元"
,
"data"
:
amount
,
"count"
:
2000
})
return
}
req
.
PaymentMethod
=
"alipay"
req
.
PaymentMethod
=
"alipay"
}
}
if
req
.
PaymentMethod
==
"wx"
{
if
req
.
PaymentMethod
==
"wx"
{
if
amount
>
2000
{
c
.
JSON
(
200
,
gin
.
H
{
"message"
:
"微信最大充值2000元"
,
"data"
:
amount
,
"count"
:
2000
})
return
}
req
.
PaymentMethod
=
"wxpay"
req
.
PaymentMethod
=
"wxpay"
}
}
returnUrl
,
_
:=
url
.
Parse
(
"https://nekoapi.com
/log"
)
returnUrl
,
_
:=
url
.
Parse
(
common
.
ServerAddress
+
"
/log"
)
notifyUrl
,
_
:=
url
.
Parse
(
"https://nekoapi.com
/api/user/epay/notify"
)
notifyUrl
,
_
:=
url
.
Parse
(
common
.
ServerAddress
+
"
/api/user/epay/notify"
)
tradeNo
:=
strconv
.
FormatInt
(
time
.
Now
()
.
Unix
(),
10
)
tradeNo
:=
strconv
.
FormatInt
(
time
.
Now
()
.
Unix
(),
10
)
payMoney
:=
amount
payMoney
:=
amount
//if payMoney < 400 {
client
:=
GetEpayClient
()
// payMoney = amount * 0.99
if
client
==
nil
{
// if amount-payMoney > 2 {
c
.
JSON
(
200
,
gin
.
H
{
"message"
:
"error"
,
"data"
:
"当前管理员未配置支付信息"
})
// payMoney = amount - 2
return
// }
}
//}
uri
,
params
,
err
:=
client
.
Purchase
(
&
epay
.
PurchaseArgs
{
uri
,
params
,
err
:=
client
.
Purchase
(
&
epay
.
PurchaseArgs
{
Type
:
epay
.
PurchaseType
(
req
.
PaymentMethod
),
Type
:
epay
.
PurchaseType
(
req
.
PaymentMethod
),
ServiceTradeNo
:
"A"
+
tradeNo
,
ServiceTradeNo
:
"A"
+
tradeNo
,
...
@@ -126,6 +104,14 @@ func EpayNotify(c *gin.Context) {
...
@@ -126,6 +104,14 @@ func EpayNotify(c *gin.Context) {
r
[
t
]
=
c
.
Request
.
URL
.
Query
()
.
Get
(
t
)
r
[
t
]
=
c
.
Request
.
URL
.
Query
()
.
Get
(
t
)
return
r
return
r
},
map
[
string
]
string
{})
},
map
[
string
]
string
{})
client
:=
GetEpayClient
()
if
client
==
nil
{
log
.
Println
(
"易支付回调失败 未找到配置信息"
)
_
,
err
:=
c
.
Writer
.
Write
([]
byte
(
"fail"
))
if
err
!=
nil
{
log
.
Println
(
"易支付回调写入失败"
)
}
}
verifyInfo
,
err
:=
client
.
Verify
(
params
)
verifyInfo
,
err
:=
client
.
Verify
(
params
)
if
err
==
nil
&&
verifyInfo
.
VerifyStatus
{
if
err
==
nil
&&
verifyInfo
.
VerifyStatus
{
_
,
err
:=
c
.
Writer
.
Write
([]
byte
(
"success"
))
_
,
err
:=
c
.
Writer
.
Write
([]
byte
(
"success"
))
...
@@ -168,20 +154,9 @@ func RequestAmount(c *gin.Context) {
...
@@ -168,20 +154,9 @@ func RequestAmount(c *gin.Context) {
var
req
AmountRequest
var
req
AmountRequest
err
:=
c
.
ShouldBindJSON
(
&
req
)
err
:=
c
.
ShouldBindJSON
(
&
req
)
if
err
!=
nil
{
if
err
!=
nil
{
c
.
JSON
(
200
,
gin
.
H
{
"message"
:
err
.
Error
(),
"data"
:
10
})
c
.
JSON
(
200
,
gin
.
H
{
"message"
:
"error"
,
"data"
:
"参数错误"
})
return
return
}
}
id
:=
c
.
GetInt
(
"id"
)
if
id
!=
1
{
if
req
.
Amount
<
10
{
c
.
JSON
(
200
,
gin
.
H
{
"message"
:
"最小充值10刀"
,
"data"
:
GetAmount
(
id
,
10
,
req
.
TopUpCode
),
"count"
:
10
})
return
}
//if req.Amount > 1500 {
// c.JSON(200, gin.H{"message": "最大充值1000刀", "data": GetAmount(id, 1000, req.TopUpCode), "count": 1500})
// return
//}
}
c
.
JSON
(
200
,
gin
.
H
{
"message"
:
"success"
,
"data"
:
GetAmount
(
id
,
float64
(
req
.
Amount
),
req
.
TopUpCode
)})
c
.
JSON
(
200
,
gin
.
H
{
"message"
:
"success"
,
"data"
:
GetAmount
(
float64
(
req
.
Amount
)
)})
}
}
middleware/distributor.go
View file @
f73ecc57
...
@@ -95,51 +95,21 @@ func Distribute() func(c *gin.Context) {
...
@@ -95,51 +95,21 @@ func Distribute() func(c *gin.Context) {
modelRequest
.
Model
=
"dall-e"
modelRequest
.
Model
=
"dall-e"
}
}
}
}
isStable
:=
false
channel
,
err
=
model
.
CacheGetRandomSatisfiedChannel
(
userGroup
,
modelRequest
.
Model
)
channel
,
err
=
model
.
CacheGetRandomSatisfiedChannel
(
userGroup
,
modelRequest
.
Model
)
c
.
Set
(
"stable"
,
false
)
if
err
!=
nil
{
if
err
!=
nil
{
message
:=
fmt
.
Sprintf
(
"当前分组 %s 下对于模型 %s 无可用渠道"
,
userGroup
,
modelRequest
.
Model
)
message
:=
fmt
.
Sprintf
(
"当前分组 %s 下对于模型 %s 无可用渠道"
,
userGroup
,
modelRequest
.
Model
)
if
strings
.
HasPrefix
(
modelRequest
.
Model
,
"gpt-4"
)
{
if
channel
!=
nil
{
common
.
SysLog
(
"GPT-4低价渠道宕机,正在尝试转换"
)
common
.
SysError
(
fmt
.
Sprintf
(
"渠道不存在:%d"
,
channel
.
Id
))
nowUser
,
err
:=
model
.
GetUserById
(
userId
,
false
)
message
=
"数据库一致性已被破坏,请联系管理员"
if
err
==
nil
{
if
nowUser
.
StableMode
{
userGroup
=
"svip"
//stableRatio = (common.StablePrice / common.BasePrice) * modelRatio
userMaxPrice
,
_
:=
strconv
.
ParseFloat
(
nowUser
.
MaxPrice
,
64
)
if
userMaxPrice
<
common
.
StablePrice
{
message
=
"当前低价通道不可用,稳定渠道价格为"
+
strconv
.
FormatFloat
(
common
.
StablePrice
,
'f'
,
-
1
,
64
)
+
"R/刀"
}
else
{
//common.SysLog(fmt.Sprintf("用户 %s 使用稳定渠道", nowUser.Username))
channel
,
err
=
model
.
CacheGetRandomSatisfiedChannel
(
userGroup
,
modelRequest
.
Model
)
if
err
!=
nil
{
message
=
"稳定渠道已经宕机,请联系管理员"
}
isStable
=
true
common
.
SysLog
(
fmt
.
Sprintf
(
"用户 %s 使用稳定渠道 %v"
,
nowUser
.
Username
,
channel
))
c
.
Set
(
"stable"
,
true
)
}
}
else
{
message
=
"当前低价通道不可用,请稍后再试,或者在后台开启稳定渠道模式"
}
}
}
//if channel == nil {
// common.SysError(fmt.Sprintf("渠道不存在:%d", channel.Id))
// message = "数据库一致性已被破坏,请联系管理员"
//}
if
!
isStable
{
c
.
JSON
(
http
.
StatusInternalServerError
,
gin
.
H
{
"error"
:
gin
.
H
{
"message"
:
message
,
"type"
:
"one_api_error"
,
},
})
c
.
Abort
()
return
}
}
c
.
JSON
(
http
.
StatusServiceUnavailable
,
gin
.
H
{
"error"
:
gin
.
H
{
"message"
:
message
,
"type"
:
"one_api_error"
,
},
})
c
.
Abort
()
return
}
}
}
}
c
.
Set
(
"channel"
,
channel
.
Type
)
c
.
Set
(
"channel"
,
channel
.
Type
)
...
...
model/midjourney.go
View file @
f73ecc57
...
@@ -17,6 +17,7 @@ type Midjourney struct {
...
@@ -17,6 +17,7 @@ type Midjourney struct {
Status
string
`json:"status"`
Status
string
`json:"status"`
Progress
string
`json:"progress"`
Progress
string
`json:"progress"`
FailReason
string
`json:"fail_reason"`
FailReason
string
`json:"fail_reason"`
ChannelId
int
`json:"channel_id"`
}
}
func
GetAllUserTask
(
userId
int
,
startIdx
int
,
num
int
)
[]
*
Midjourney
{
func
GetAllUserTask
(
userId
int
,
startIdx
int
,
num
int
)
[]
*
Midjourney
{
...
...
model/option.go
View file @
f73ecc57
...
@@ -53,6 +53,10 @@ func InitOptionMap() {
...
@@ -53,6 +53,10 @@ func InitOptionMap() {
common
.
OptionMap
[
"SystemName"
]
=
common
.
SystemName
common
.
OptionMap
[
"SystemName"
]
=
common
.
SystemName
common
.
OptionMap
[
"Logo"
]
=
common
.
Logo
common
.
OptionMap
[
"Logo"
]
=
common
.
Logo
common
.
OptionMap
[
"ServerAddress"
]
=
""
common
.
OptionMap
[
"ServerAddress"
]
=
""
common
.
OptionMap
[
"PayAddress"
]
=
""
common
.
OptionMap
[
"EpayId"
]
=
""
common
.
OptionMap
[
"EpayKey"
]
=
""
common
.
OptionMap
[
"Price"
]
=
strconv
.
Itoa
(
common
.
Price
)
common
.
OptionMap
[
"GitHubClientId"
]
=
""
common
.
OptionMap
[
"GitHubClientId"
]
=
""
common
.
OptionMap
[
"GitHubClientSecret"
]
=
""
common
.
OptionMap
[
"GitHubClientSecret"
]
=
""
common
.
OptionMap
[
"WeChatServerAddress"
]
=
""
common
.
OptionMap
[
"WeChatServerAddress"
]
=
""
...
@@ -71,9 +75,6 @@ func InitOptionMap() {
...
@@ -71,9 +75,6 @@ func InitOptionMap() {
common
.
OptionMap
[
"ChatLink"
]
=
common
.
ChatLink
common
.
OptionMap
[
"ChatLink"
]
=
common
.
ChatLink
common
.
OptionMap
[
"QuotaPerUnit"
]
=
strconv
.
FormatFloat
(
common
.
QuotaPerUnit
,
'f'
,
-
1
,
64
)
common
.
OptionMap
[
"QuotaPerUnit"
]
=
strconv
.
FormatFloat
(
common
.
QuotaPerUnit
,
'f'
,
-
1
,
64
)
common
.
OptionMap
[
"RetryTimes"
]
=
strconv
.
Itoa
(
common
.
RetryTimes
)
common
.
OptionMap
[
"RetryTimes"
]
=
strconv
.
Itoa
(
common
.
RetryTimes
)
common
.
OptionMap
[
"NormalPrice"
]
=
strconv
.
FormatFloat
(
common
.
NormalPrice
,
'f'
,
-
1
,
64
)
common
.
OptionMap
[
"StablePrice"
]
=
strconv
.
FormatFloat
(
common
.
StablePrice
,
'f'
,
-
1
,
64
)
common
.
OptionMap
[
"BasePrice"
]
=
strconv
.
FormatFloat
(
common
.
BasePrice
,
'f'
,
-
1
,
64
)
common
.
OptionMapRWMutex
.
Unlock
()
common
.
OptionMapRWMutex
.
Unlock
()
loadOptionsFromDatabase
()
loadOptionsFromDatabase
()
...
@@ -157,8 +158,6 @@ func updateOptionMap(key string, value string) (err error) {
...
@@ -157,8 +158,6 @@ func updateOptionMap(key string, value string) (err error) {
common
.
LogConsumeEnabled
=
boolValue
common
.
LogConsumeEnabled
=
boolValue
case
"DisplayInCurrencyEnabled"
:
case
"DisplayInCurrencyEnabled"
:
common
.
DisplayInCurrencyEnabled
=
boolValue
common
.
DisplayInCurrencyEnabled
=
boolValue
case
"DisplayTokenStatEnabled"
:
common
.
DisplayTokenStatEnabled
=
boolValue
}
}
}
}
switch
key
{
switch
key
{
...
@@ -177,6 +176,14 @@ func updateOptionMap(key string, value string) (err error) {
...
@@ -177,6 +176,14 @@ func updateOptionMap(key string, value string) (err error) {
common
.
SMTPToken
=
value
common
.
SMTPToken
=
value
case
"ServerAddress"
:
case
"ServerAddress"
:
common
.
ServerAddress
=
value
common
.
ServerAddress
=
value
case
"PayAddress"
:
common
.
PayAddress
=
value
case
"EpayId"
:
common
.
EpayId
=
value
case
"EpayKey"
:
common
.
EpayKey
=
value
case
"Price"
:
common
.
Price
,
_
=
strconv
.
Atoi
(
value
)
case
"GitHubClientId"
:
case
"GitHubClientId"
:
common
.
GitHubClientId
=
value
common
.
GitHubClientId
=
value
case
"GitHubClientSecret"
:
case
"GitHubClientSecret"
:
...
@@ -217,12 +224,6 @@ func updateOptionMap(key string, value string) (err error) {
...
@@ -217,12 +224,6 @@ func updateOptionMap(key string, value string) (err error) {
common
.
TopUpLink
=
value
common
.
TopUpLink
=
value
case
"ChatLink"
:
case
"ChatLink"
:
common
.
ChatLink
=
value
common
.
ChatLink
=
value
case
"NormalPrice"
:
common
.
NormalPrice
,
_
=
strconv
.
ParseFloat
(
value
,
64
)
case
"BasePrice"
:
common
.
BasePrice
,
_
=
strconv
.
ParseFloat
(
value
,
64
)
case
"StablePrice"
:
common
.
StablePrice
,
_
=
strconv
.
ParseFloat
(
value
,
64
)
case
"ChannelDisableThreshold"
:
case
"ChannelDisableThreshold"
:
common
.
ChannelDisableThreshold
,
_
=
strconv
.
ParseFloat
(
value
,
64
)
common
.
ChannelDisableThreshold
,
_
=
strconv
.
ParseFloat
(
value
,
64
)
case
"QuotaPerUnit"
:
case
"QuotaPerUnit"
:
...
...
web/src/components/PersonalSetting.js
View file @
f73ecc57
import
React
,
{
useContext
,
useEffect
,
useState
}
from
'react'
;
import
React
,
{
useContext
,
useEffect
,
useState
}
from
'react'
;
import
{
Button
,
Input
,
Checkbox
,
Divider
,
Form
,
Header
,
Image
,
Message
,
Modal
}
from
'semantic-ui-react'
;
import
{
Button
,
Divider
,
Form
,
Header
,
Image
,
Message
,
Modal
}
from
'semantic-ui-react'
;
import
{
Link
,
useNavigate
}
from
'react-router-dom'
;
import
{
Link
,
useNavigate
}
from
'react-router-dom'
;
import
{
API
,
copy
,
showError
,
showInfo
,
showNotice
,
showSuccess
}
from
'../helpers'
;
import
{
API
,
copy
,
showError
,
showInfo
,
showNotice
,
showSuccess
}
from
'../helpers'
;
import
Turnstile
from
'react-turnstile'
;
import
Turnstile
from
'react-turnstile'
;
import
{
UserContext
}
from
'../context/User'
;
import
{
UserContext
}
from
'../context/User'
;
const
PersonalSetting
=
()
=>
{
const
PersonalSetting
=
()
=>
{
const
[
userState
,
userDispatch
]
=
useContext
(
UserContext
);
const
[
userState
,
userDispatch
]
=
useContext
(
UserContext
);
let
navigate
=
useNavigate
();
let
navigate
=
useNavigate
();
const
[
inputs
,
setInputs
]
=
useState
({
const
[
inputs
,
setInputs
]
=
useState
({
wechat_verification_code
:
''
,
wechat_verification_code
:
''
,
...
@@ -15,10 +15,6 @@ const PersonalSetting = () => {
...
@@ -15,10 +15,6 @@ const PersonalSetting = () => {
email
:
''
,
email
:
''
,
self_account_deletion_confirmation
:
''
self_account_deletion_confirmation
:
''
});
});
const
[
stableMode
,
setStableMode
]
=
useState
({
stableMode
:
false
,
maxPrice
:
7
,
});
const
[
status
,
setStatus
]
=
useState
({});
const
[
status
,
setStatus
]
=
useState
({});
const
[
showWeChatBindModal
,
setShowWeChatBindModal
]
=
useState
(
false
);
const
[
showWeChatBindModal
,
setShowWeChatBindModal
]
=
useState
(
false
);
const
[
showEmailBindModal
,
setShowEmailBindModal
]
=
useState
(
false
);
const
[
showEmailBindModal
,
setShowEmailBindModal
]
=
useState
(
false
);
...
@@ -29,12 +25,8 @@ const PersonalSetting = () => {
...
@@ -29,12 +25,8 @@ const PersonalSetting = () => {
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
disableButton
,
setDisableButton
]
=
useState
(
false
);
const
[
disableButton
,
setDisableButton
]
=
useState
(
false
);
const
[
countdown
,
setCountdown
]
=
useState
(
30
);
const
[
countdown
,
setCountdown
]
=
useState
(
30
);
const
[
affLink
,
setAffLink
]
=
useState
(
""
);
const
[
affLink
,
setAffLink
]
=
useState
(
""
);
const
[
systemToken
,
setSystemToken
]
=
useState
(
""
);
const
[
systemToken
,
setSystemToken
]
=
useState
(
""
);
// setStableMode(userState.user.stableMode, userState.user.maxPrice);
console
.
log
(
userState
.
user
)
useEffect
(()
=>
{
useEffect
(()
=>
{
let
status
=
localStorage
.
getItem
(
'status'
);
let
status
=
localStorage
.
getItem
(
'status'
);
...
@@ -46,9 +38,6 @@ const PersonalSetting = () => {
...
@@ -46,9 +38,6 @@ const PersonalSetting = () => {
setTurnstileSiteKey
(
status
.
turnstile_site_key
);
setTurnstileSiteKey
(
status
.
turnstile_site_key
);
}
}
}
}
// if (userState.user !== undefined) {
// setStableMode(userState.user.stable_mode, userState.user.max_price);
// }
},
[]);
},
[]);
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -64,30 +53,17 @@ const PersonalSetting = () => {
...
@@ -64,30 +53,17 @@ const PersonalSetting = () => {
return
()
=>
clearInterval
(
countdownInterval
);
// Clean up on unmount
return
()
=>
clearInterval
(
countdownInterval
);
// Clean up on unmount
},
[
disableButton
,
countdown
]);
},
[
disableButton
,
countdown
]);
useEffect
(()
=>
{
const
handleInputChange
=
(
e
,
{
name
,
value
})
=>
{
if
(
userState
.
user
!==
undefined
)
{
setInputs
((
inputs
)
=>
({
...
inputs
,
[
name
]:
value
}));
setStableMode
({
stableMode
:
userState
.
user
.
stable_mode
,
maxPrice
:
userState
.
user
.
max_price
})
// if (stableMode.localMaxPrice !== userState.user.max_price) {
// setStableMode({
// localMaxPrice: userState.user.max_price
// })
// }
}
},
[
userState
]);
const
handleInputChange
=
(
e
,
{
name
,
value
})
=>
{
setInputs
((
inputs
)
=>
({...
inputs
,
[
name
]:
value
}));
};
};
const
generateAccessToken
=
async
()
=>
{
const
generateAccessToken
=
async
()
=>
{
const
res
=
await
API
.
get
(
'/api/user/token'
);
const
res
=
await
API
.
get
(
'/api/user/token'
);
const
{
success
,
message
,
data
}
=
res
.
data
;
const
{
success
,
message
,
data
}
=
res
.
data
;
if
(
success
)
{
if
(
success
)
{
setSystemToken
(
data
);
setSystemToken
(
data
);
setAffLink
(
""
);
await
copy
(
data
);
setAffLink
(
""
);
await
copy
(
data
);
showSuccess
(
`令牌已重置并已复制到剪贴板`
);
showSuccess
(
`令牌已重置并已复制到剪贴板`
);
}
else
{
}
else
{
showError
(
message
);
showError
(
message
);
...
@@ -96,11 +72,12 @@ const PersonalSetting = () => {
...
@@ -96,11 +72,12 @@ const PersonalSetting = () => {
const
getAffLink
=
async
()
=>
{
const
getAffLink
=
async
()
=>
{
const
res
=
await
API
.
get
(
'/api/user/aff'
);
const
res
=
await
API
.
get
(
'/api/user/aff'
);
const
{
success
,
message
,
data
}
=
res
.
data
;
const
{
success
,
message
,
data
}
=
res
.
data
;
if
(
success
)
{
if
(
success
)
{
let
link
=
`
${
window
.
location
.
origin
}
/register?aff=
${
data
}
`
;
let
link
=
`
${
window
.
location
.
origin
}
/register?aff=
${
data
}
`
;
setAffLink
(
link
);
setAffLink
(
link
);
setSystemToken
(
""
);
await
copy
(
link
);
setSystemToken
(
""
);
await
copy
(
link
);
showSuccess
(
`邀请链接已复制到剪切板`
);
showSuccess
(
`邀请链接已复制到剪切板`
);
}
else
{
}
else
{
showError
(
message
);
showError
(
message
);
...
@@ -108,95 +85,95 @@ const PersonalSetting = () => {
...
@@ -108,95 +85,95 @@ const PersonalSetting = () => {
};
};
const
handleAffLinkClick
=
async
(
e
)
=>
{
const
handleAffLinkClick
=
async
(
e
)
=>
{
e
.
target
.
select
();
e
.
target
.
select
();
await
copy
(
e
.
target
.
value
);
await
copy
(
e
.
target
.
value
);
showSuccess
(
`邀请链接已复制到剪切板`
);
showSuccess
(
`邀请链接已复制到剪切板`
);
};
};
const
handleSystemTokenClick
=
async
(
e
)
=>
{
e
.
target
.
select
();
await
copy
(
e
.
target
.
value
);
showSuccess
(
`系统令牌已复制到剪切板`
);
};
const
handleSystemTokenClick
=
async
(
e
)
=>
{
const
deleteAccount
=
async
()
=>
{
e
.
target
.
select
();
await
copy
(
e
.
target
.
value
);
showSuccess
(
`系统令牌已复制到剪切板`
);
};
const
deleteAccount
=
async
()
=>
{
if
(
inputs
.
self_account_deletion_confirmation
!==
userState
.
user
.
username
)
{
if
(
inputs
.
self_account_deletion_confirmation
!==
userState
.
user
.
username
)
{
showError
(
'请输入你的账户名以确认删除!'
);
showError
(
'请输入你的账户名以确认删除!'
);
return
;
return
;
}
}
const
res
=
await
API
.
delete
(
'/api/user/self'
);
const
res
=
await
API
.
delete
(
'/api/user/self'
);
const
{
success
,
message
}
=
res
.
data
;
const
{
success
,
message
}
=
res
.
data
;
if
(
success
)
{
if
(
success
)
{
showSuccess
(
'账户已删除!'
);
showSuccess
(
'账户已删除!'
);
await
API
.
get
(
'/api/user/logout'
);
await
API
.
get
(
'/api/user/logout'
);
userDispatch
({
type
:
'logout'
});
userDispatch
({
type
:
'logout'
});
localStorage
.
removeItem
(
'user'
);
localStorage
.
removeItem
(
'user'
);
navigate
(
'/login'
);
navigate
(
'/login'
);
}
else
{
}
else
{
showError
(
message
);
showError
(
message
);
}
}
};
};
const
bindWeChat
=
async
()
=>
{
if
(
inputs
.
wechat_verification_code
===
''
)
return
;
const
res
=
await
API
.
get
(
`/api/oauth/wechat/bind?code=
${
inputs
.
wechat_verification_code
}
`
);
const
{
success
,
message
}
=
res
.
data
;
if
(
success
)
{
showSuccess
(
'微信账户绑定成功!'
);
setShowWeChatBindModal
(
false
);
}
else
{
showError
(
message
);
}
};
const
openGitHubOAuth
=
()
=>
{
const
bindWeChat
=
async
()
=>
{
window
.
open
(
if
(
inputs
.
wechat_verification_code
===
''
)
return
;
`https://github.com/login/oauth/authorize?client_id=
${
status
.
github_client_id
}
&scope=user:email`
const
res
=
await
API
.
get
(
);
`/api/oauth/wechat/bind?code=
${
inputs
.
wechat_verification_code
}
`
};
);
const
{
success
,
message
}
=
res
.
data
;
if
(
success
)
{
showSuccess
(
'微信账户绑定成功!'
);
setShowWeChatBindModal
(
false
);
}
else
{
showError
(
message
);
}
};
const
sendVerificationCode
=
async
()
=>
{
const
openGitHubOAuth
=
()
=>
{
setDisableButton
(
true
);
window
.
open
(
if
(
inputs
.
email
===
''
)
return
;
`https://github.com/login/oauth/authorize?client_id=
${
status
.
github_client_id
}
&scope=user:email`
if
(
turnstileEnabled
&&
turnstileToken
===
''
)
{
);
showInfo
(
'请稍后几秒重试,Turnstile 正在检查用户环境!'
);
};
return
;
}
setLoading
(
true
);
const
res
=
await
API
.
get
(
`/api/verification?email=
${
inputs
.
email
}
&turnstile=
${
turnstileToken
}
`
);
const
{
success
,
message
}
=
res
.
data
;
if
(
success
)
{
showSuccess
(
'验证码发送成功,请检查邮箱!'
);
}
else
{
showError
(
message
);
}
setLoading
(
false
);
};
const
bindEmail
=
async
()
=>
{
const
sendVerificationCode
=
async
()
=>
{
if
(
inputs
.
email_verification_code
===
''
)
return
;
setDisableButton
(
true
);
setLoading
(
true
);
if
(
inputs
.
email
===
''
)
return
;
const
res
=
await
API
.
get
(
if
(
turnstileEnabled
&&
turnstileToken
===
''
)
{
`/api/oauth/email/bind?email=
${
inputs
.
email
}
&code=
${
inputs
.
email_verification_code
}
`
showInfo
(
'请稍后几秒重试,Turnstile 正在检查用户环境!'
);
);
return
;
const
{
success
,
message
}
=
res
.
data
;
}
if
(
success
)
{
setLoading
(
true
);
showSuccess
(
'邮箱账户绑定成功!'
);
const
res
=
await
API
.
get
(
setShowEmailBindModal
(
false
);
`/api/verification?email=
${
inputs
.
email
}
&turnstile=
${
turnstileToken
}
`
}
else
{
);
showError
(
message
);
const
{
success
,
message
}
=
res
.
data
;
}
if
(
success
)
{
setLoading
(
false
);
showSuccess
(
'验证码发送成功,请检查邮箱!'
);
};
}
else
{
showError
(
message
);
}
setLoading
(
false
);
};
// const setStableMod = ;
const
bindEmail
=
async
()
=>
{
if
(
inputs
.
email_verification_code
===
''
)
return
;
setLoading
(
true
);
const
res
=
await
API
.
get
(
`/api/oauth/email/bind?email=
${
inputs
.
email
}
&code=
${
inputs
.
email_verification_code
}
`
);
const
{
success
,
message
}
=
res
.
data
;
if
(
success
)
{
showSuccess
(
'邮箱账户绑定成功!'
);
setShowEmailBindModal
(
false
);
}
else
{
showError
(
message
);
}
setLoading
(
false
);
};
return
(
return
(
<
div
style
=
{{
lineHeight
:
'40px'
}}
>
<
div
style
=
{{
lineHeight
:
'40px'
}}
>
<
Header
as
=
'h3'
>
通用设置
<
/Header
>
<
Header
as
=
'h3'
>
通用设置
<
/Header
>
<
Message
>
<
Message
>
注意,此处生成的令牌用于系统管理,而非用于请求
OpenAI
相关的服务,请知悉。
注意,此处生成的令牌用于系统管理,而非用于请求
OpenAI
相关的服务,请知悉。
...
@@ -209,84 +186,26 @@ const PersonalSetting = () => {
...
@@ -209,84 +186,26 @@ const PersonalSetting = () => {
<
Button
onClick
=
{()
=>
{
<
Button
onClick
=
{()
=>
{
setShowAccountDeleteModal
(
true
);
setShowAccountDeleteModal
(
true
);
}}
>
删除个人账户
<
/Button
>
}}
>
删除个人账户
<
/Button
>
<
Divider
/>
<
Header
as
=
'h3'
>
GPT
-
4
消费设置
<
/Header
>
<
Form
>
<
Form
.
Field
>
<
Checkbox
label
=
"启用稳定模式(当低价渠道宕机时,自动选择已开启的渠道,以保证稳定性,仅影响GPT-4)"
checked
=
{
stableMode
.
stableMode
}
onChange
=
{
(
e
,
data
)
=>
{
setStableMode
({
...
stableMode
,
stableMode
:
data
.
checked
})
}
}
><
/Checkbox
>
<
/Form.Field
>
<
Form
.
Field
control
=
{
Input
}
label
=
'最高接受价格(n元/刀)'
placeholder
=
'7'
type
=
{
'number'
}
value
=
{
stableMode
.
maxPrice
}
onChange
=
{
(
e
,
data
)
=>
{
setStableMode
({
...
stableMode
,
maxPrice
:
data
.
value
})
}
}
>
{
/*<label></label>*/
}
{
/*<input placeholder='7' value= {stableMode.maxPrice}/>*/
}
<
/Form.Field
>
<
Button
type
=
'submit'
onClick
=
{
async
(
e
,
data
)
=>
{
if
(
stableMode
.
localMaxPrice
===
''
)
return
;
// console.log(data)
// post to /api/user/set_stable_mode
const
res
=
await
API
.
post
(
`/api/user/set_stable_mode`
,
stableMode
)
const
{
success
,
message
}
=
res
.
data
;
if
(
success
)
{
// userDispatch({type: 'stable_mode', payload: stableMode})
userState
.
user
.
stable_mode
=
stableMode
.
stableMode
userState
.
user
.
max_price
=
stableMode
.
maxPrice
localStorage
.
setItem
(
'user'
,
JSON
.
stringify
(
userState
.
user
));
showSuccess
(
'设置成功!'
);
}
else
{
showError
(
message
);
}
}
}
>
保存消费设置
<
/Button
>
<
/Form
>
{
/*<Checkbox label="启用稳定模式(当低价渠道宕机时,自动选择已开启的渠道,以保证稳定性)" onChange={*/
}
{
/* (e, data) => {*/
}
{
/* // if (inputs.email_verification_code === '') return;*/
}
{
/* console.log(data)*/
}
{
/* }*/
}
{
/*}></Checkbox>*/
}
{
/*<Input label="最高接受价格(n元/刀)" type="integer"></Input>*/
}
{
systemToken
&&
(
{
systemToken
&&
(
<
Form
.
Input
<
Form
.
Input
fluid
fluid
readOnly
readOnly
value
=
{
systemToken
}
value
=
{
systemToken
}
onClick
=
{
handleSystemTokenClick
}
onClick
=
{
handleSystemTokenClick
}
style
=
{{
marginTop
:
'10px'
}}
style
=
{{
marginTop
:
'10px'
}}
/
>
/
>
)}
)}
{
affLink
&&
(
{
affLink
&&
(
<
Form
.
Input
<
Form
.
Input
fluid
fluid
readOnly
readOnly
value
=
{
affLink
}
value
=
{
affLink
}
onClick
=
{
handleAffLinkClick
}
onClick
=
{
handleAffLinkClick
}
style
=
{{
marginTop
:
'10px'
}}
style
=
{{
marginTop
:
'10px'
}}
/
>
/
>
)}
<
Divider
/>
)}
<
Divider
/>
<
Header
as
=
'h3'
>
账号绑定
<
/Header
>
<
Header
as
=
'h3'
>
账号绑定
<
/Header
>
{
{
status
.
wechat_login
&&
(
status
.
wechat_login
&&
(
...
@@ -307,8 +226,8 @@ const PersonalSetting = () => {
...
@@ -307,8 +226,8 @@ const PersonalSetting = () => {
>
>
<
Modal
.
Content
>
<
Modal
.
Content
>
<
Modal
.
Description
>
<
Modal
.
Description
>
<
Image
src
=
{
status
.
wechat_qrcode
}
fluid
/>
<
Image
src
=
{
status
.
wechat_qrcode
}
fluid
/>
<
div
style
=
{{
textAlign
:
'center'
}}
>
<
div
style
=
{{
textAlign
:
'center'
}}
>
<
p
>
<
p
>
微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)
微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)
<
/p
>
<
/p
>
...
@@ -345,7 +264,7 @@ const PersonalSetting = () => {
...
@@ -345,7 +264,7 @@ const PersonalSetting = () => {
onOpen
=
{()
=>
setShowEmailBindModal
(
true
)}
onOpen
=
{()
=>
setShowEmailBindModal
(
true
)}
open
=
{
showEmailBindModal
}
open
=
{
showEmailBindModal
}
size
=
{
'tiny'
}
size
=
{
'tiny'
}
style
=
{{
maxWidth
:
'450px'
}}
style
=
{{
maxWidth
:
'450px'
}}
>
>
<
Modal
.
Header
>
绑定邮箱地址
<
/Modal.Header
>
<
Modal
.
Header
>
绑定邮箱地址
<
/Modal.Header
>
<
Modal
.
Content
>
<
Modal
.
Content
>
...
@@ -381,25 +300,25 @@ const PersonalSetting = () => {
...
@@ -381,25 +300,25 @@ const PersonalSetting = () => {
<><
/
>
<><
/
>
)}
)}
<
div
style
=
{{
display
:
'flex'
,
justifyContent
:
'space-between'
,
marginTop
:
'1rem'
}}
>
<
div
style
=
{{
display
:
'flex'
,
justifyContent
:
'space-between'
,
marginTop
:
'1rem'
}}
>
<
Button
<
Button
color
=
''
color
=
''
fluid
fluid
size
=
'large'
size
=
'large'
onClick
=
{
bindEmail
}
onClick
=
{
bindEmail
}
loading
=
{
loading
}
loading
=
{
loading
}
>
>
确认绑定
确认绑定
<
/Button
>
<
/Button
>
<
div
style
=
{{
width
:
'1rem'
}}
><
/div
>
<
div
style
=
{{
width
:
'1rem'
}}
><
/div
>
<
Button
<
Button
fluid
fluid
size
=
'large'
size
=
'large'
onClick
=
{()
=>
setShowEmailBindModal
(
false
)}
onClick
=
{()
=>
setShowEmailBindModal
(
false
)}
>
>
取消
取消
<
/Button
>
<
/Button
>
<
/div
>
<
/div
>
<
/Form
>
<
/Form
>
<
/Modal.Description
>
<
/Modal.Description
>
<
/Modal.Content
>
<
/Modal.Content
>
<
/Modal
>
<
/Modal
>
...
@@ -408,11 +327,11 @@ const PersonalSetting = () => {
...
@@ -408,11 +327,11 @@ const PersonalSetting = () => {
onOpen
=
{()
=>
setShowAccountDeleteModal
(
true
)}
onOpen
=
{()
=>
setShowAccountDeleteModal
(
true
)}
open
=
{
showAccountDeleteModal
}
open
=
{
showAccountDeleteModal
}
size
=
{
'tiny'
}
size
=
{
'tiny'
}
style
=
{{
maxWidth
:
'450px'
}}
style
=
{{
maxWidth
:
'450px'
}}
>
>
<
Modal
.
Header
>
危险操作
<
/Modal.Header
>
<
Modal
.
Header
>
危险操作
<
/Modal.Header
>
<
Modal
.
Content
>
<
Modal
.
Content
>
<
Message
>
您正在删除自己的帐户,将清空所有数据且不可恢复
<
/Message
>
<
Message
>
您正在删除自己的帐户,将清空所有数据且不可恢复
<
/Message
>
<
Modal
.
Description
>
<
Modal
.
Description
>
<
Form
size
=
'large'
>
<
Form
size
=
'large'
>
<
Form
.
Input
<
Form
.
Input
...
@@ -431,24 +350,26 @@ const PersonalSetting = () => {
...
@@ -431,24 +350,26 @@ const PersonalSetting = () => {
/>
/>
) : (
) : (
<></>
<></>
)}<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: '1rem' }}>
)}
<Button
<div style={{ display: 'flex', justifyContent: 'space-between', marginTop: '1rem' }}>
color='red'
<Button
fluid
color='red'
size='large'
fluid
onClick={deleteAccount}
size='large'
loading={loading}
onClick={deleteAccount}
>
loading={loading}
确认删除
>
</Button><div style={{ width: '1rem' }}></div>
确认删除
<Button
</Button>
fluid
<div style={{ width: '1rem' }}></div>
size='large'
<Button
onClick={() => setShowAccountDeleteModal(false)}
fluid
>
size='large'
取消
onClick={() => setShowAccountDeleteModal(false)}
</Button>
>
</div>
取消
</Button>
</div>
</Form>
</Form>
</Modal.Description>
</Modal.Description>
</Modal.Content>
</Modal.Content>
...
@@ -457,4 +378,4 @@ const PersonalSetting = () => {
...
@@ -457,4 +378,4 @@ const PersonalSetting = () => {
);
);
};
};
export default PersonalSetting;
export default PersonalSetting;
\ No newline at end of file
web/src/components/SystemSetting.js
View file @
f73ecc57
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Button
,
Divider
,
Form
,
Grid
,
Header
,
Modal
,
Message
}
from
'semantic-ui-react'
;
import
{
Button
,
Divider
,
Form
,
Grid
,
Header
,
Modal
,
Message
}
from
'semantic-ui-react'
;
import
{
API
,
removeTrailingSlash
,
showError
}
from
'../helpers'
;
import
{
API
,
removeTrailingSlash
,
showError
}
from
'../helpers'
;
const
SystemSetting
=
()
=>
{
const
SystemSetting
=
()
=>
{
let
[
inputs
,
setInputs
]
=
useState
({
let
[
inputs
,
setInputs
]
=
useState
({
PasswordLoginEnabled
:
''
,
PasswordLoginEnabled
:
''
,
PasswordRegisterEnabled
:
''
,
PasswordRegisterEnabled
:
''
,
EmailVerificationEnabled
:
''
,
EmailVerificationEnabled
:
''
,
GitHubOAuthEnabled
:
''
,
GitHubOAuthEnabled
:
''
,
GitHubClientId
:
''
,
GitHubClientId
:
''
,
GitHubClientSecret
:
''
,
GitHubClientSecret
:
''
,
Notice
:
''
,
Notice
:
''
,
SMTPServer
:
''
,
SMTPServer
:
''
,
SMTPPort
:
''
,
SMTPPort
:
''
,
SMTPAccount
:
''
,
SMTPAccount
:
''
,
SMTPFrom
:
''
,
SMTPFrom
:
''
,
SMTPToken
:
''
,
SMTPToken
:
''
,
ServerAddress
:
''
,
ServerAddress
:
''
,
Footer
:
''
,
EpayId
:
''
,
WeChatAuthEnabled
:
''
,
EpayKey
:
''
,
WeChatServerAddress
:
''
,
Price
:
''
,
WeChatServerToken
:
''
,
PayAddress
:
''
,
WeChatAccountQRCodeImageURL
:
''
,
Footer
:
''
,
TurnstileCheckEnabled
:
''
,
WeChatAuthEnabled
:
''
,
TurnstileSiteKey
:
''
,
WeChatServerAddress
:
''
,
TurnstileSecretKey
:
''
,
WeChatServerToken
:
''
,
RegisterEnabled
:
''
,
WeChatAccountQRCodeImageURL
:
''
,
EmailDomainRestrictionEnabled
:
''
,
TurnstileCheckEnabled
:
''
,
EmailDomainWhitelist
:
''
TurnstileSiteKey
:
''
,
});
TurnstileSecretKey
:
''
,
const
[
originInputs
,
setOriginInputs
]
=
useState
({});
RegisterEnabled
:
''
,
let
[
loading
,
setLoading
]
=
useState
(
false
);
EmailDomainRestrictionEnabled
:
''
,
const
[
EmailDomainWhitelist
,
setEmailDomainWhitelist
]
=
useState
([]);
EmailDomainWhitelist
:
''
const
[
restrictedDomainInput
,
setRestrictedDomainInput
]
=
useState
(
''
);
});
const
[
showPasswordWarningModal
,
setShowPasswordWarningModal
]
=
useState
(
false
);
const
[
originInputs
,
setOriginInputs
]
=
useState
({});
let
[
loading
,
setLoading
]
=
useState
(
false
);
const
[
EmailDomainWhitelist
,
setEmailDomainWhitelist
]
=
useState
([]);
const
[
restrictedDomainInput
,
setRestrictedDomainInput
]
=
useState
(
''
);
const
[
showPasswordWarningModal
,
setShowPasswordWarningModal
]
=
useState
(
false
);
const
getOptions
=
async
()
=>
{
const
getOptions
=
async
()
=>
{
const
res
=
await
API
.
get
(
'/api/option/'
);
const
res
=
await
API
.
get
(
'/api/option/'
);
const
{
success
,
message
,
data
}
=
res
.
data
;
const
{
success
,
message
,
data
}
=
res
.
data
;
if
(
success
)
{
if
(
success
)
{
let
newInputs
=
{};
let
newInputs
=
{};
data
.
forEach
((
item
)
=>
{
data
.
forEach
((
item
)
=>
{
newInputs
[
item
.
key
]
=
item
.
value
;
newInputs
[
item
.
key
]
=
item
.
value
;
});
});
setInputs
({
setInputs
({
...
newInputs
,
...
newInputs
,
EmailDomainWhitelist
:
newInputs
.
EmailDomainWhitelist
.
split
(
','
)
EmailDomainWhitelist
:
newInputs
.
EmailDomainWhitelist
.
split
(
','
)
});
});
setOriginInputs
(
newInputs
);
setOriginInputs
(
newInputs
);
setEmailDomainWhitelist
(
newInputs
.
EmailDomainWhitelist
.
split
(
','
).
map
((
item
)
=>
{
setEmailDomainWhitelist
(
newInputs
.
EmailDomainWhitelist
.
split
(
','
).
map
((
item
)
=>
{
return
{
key
:
item
,
text
:
item
,
value
:
item
};
return
{
key
:
item
,
text
:
item
,
value
:
item
};
}));
}));
}
else
{
}
else
{
showError
(
message
);
showError
(
message
);
}
}
};
};
useEffect
(()
=>
{
useEffect
(()
=>
{
getOptions
().
then
();
getOptions
().
then
();
},
[]);
},
[]);
const
updateOption
=
async
(
key
,
value
)
=>
{
const
updateOption
=
async
(
key
,
value
)
=>
{
setLoading
(
true
);
setLoading
(
true
);
switch
(
key
)
{
switch
(
key
)
{
case
'PasswordLoginEnabled'
:
case
'PasswordLoginEnabled'
:
case
'PasswordRegisterEnabled'
:
case
'PasswordRegisterEnabled'
:
case
'EmailVerificationEnabled'
:
case
'EmailVerificationEnabled'
:
case
'GitHubOAuthEnabled'
:
case
'GitHubOAuthEnabled'
:
case
'WeChatAuthEnabled'
:
case
'WeChatAuthEnabled'
:
case
'TurnstileCheckEnabled'
:
case
'TurnstileCheckEnabled'
:
case
'EmailDomainRestrictionEnabled'
:
case
'EmailDomainRestrictionEnabled'
:
case
'RegisterEnabled'
:
case
'RegisterEnabled'
:
value
=
inputs
[
key
]
===
'true'
?
'false'
:
'true'
;
value
=
inputs
[
key
]
===
'true'
?
'false'
:
'true'
;
break
;
break
;
default
:
default
:
break
;
break
;
}
}
const
res
=
await
API
.
put
(
'/api/option/'
,
{
const
res
=
await
API
.
put
(
'/api/option/'
,
{
key
,
key
,
value
value
});
});
const
{
success
,
message
}
=
res
.
data
;
const
{
success
,
message
}
=
res
.
data
;
if
(
success
)
{
if
(
success
)
{
if
(
key
===
'EmailDomainWhitelist'
)
{
if
(
key
===
'EmailDomainWhitelist'
)
{
value
=
value
.
split
(
','
);
value
=
value
.
split
(
','
);
}
}
setInputs
((
inputs
)
=>
({
setInputs
((
inputs
)
=>
({
...
inputs
,
[
key
]:
value
...
inputs
,
[
key
]:
value
}));
}));
}
else
{
}
else
{
showError
(
message
);
showError
(
message
);
}
}
setLoading
(
false
);
setLoading
(
false
);
};
};
const
handleInputChange
=
async
(
e
,
{
name
,
value
})
=>
{
const
handleInputChange
=
async
(
e
,
{
name
,
value
})
=>
{
if
(
name
===
'PasswordLoginEnabled'
&&
inputs
[
name
]
===
'true'
)
{
if
(
name
===
'PasswordLoginEnabled'
&&
inputs
[
name
]
===
'true'
)
{
// block disabling password login
// block disabling password login
setShowPasswordWarningModal
(
true
);
setShowPasswordWarningModal
(
true
);
return
;
return
;
}
}
if
(
if
(
name
===
'Notice'
||
name
===
'Notice'
||
name
.
startsWith
(
'SMTP'
)
||
name
.
startsWith
(
'SMTP'
)
||
name
===
'ServerAddress'
||
name
===
'ServerAddress'
||
name
===
'GitHubClientId'
||
name
===
'EpayId'
||
name
===
'GitHubClientSecret'
||
name
===
'EpayKey'
||
name
===
'WeChatServerAddress'
||
name
===
'Price'
||
name
===
'WeChatServerToken'
||
name
===
'PayAddress'
||
name
===
'WeChatAccountQRCodeImageURL'
||
name
===
'GitHubClientId'
||
name
===
'TurnstileSiteKey'
||
name
===
'GitHubClientSecret'
||
name
===
'TurnstileSecretKey'
||
name
===
'WeChatServerAddress'
||
name
===
'EmailDomainWhitelist'
name
===
'WeChatServerToken'
||
)
{
name
===
'WeChatAccountQRCodeImageURL'
||
setInputs
((
inputs
)
=>
({
...
inputs
,
[
name
]:
value
}));
name
===
'TurnstileSiteKey'
||
}
else
{
name
===
'TurnstileSecretKey'
||
await
updateOption
(
name
,
value
);
name
===
'EmailDomainWhitelist'
}
)
{
};
setInputs
((
inputs
)
=>
({...
inputs
,
[
name
]:
value
}));
}
else
{
await
updateOption
(
name
,
value
);
}
};
const
submitServerAddress
=
async
()
=>
{
const
submitServerAddress
=
async
()
=>
{
let
ServerAddress
=
removeTrailingSlash
(
inputs
.
ServerAddress
);
let
ServerAddress
=
removeTrailingSlash
(
inputs
.
ServerAddress
);
await
updateOption
(
'ServerAddress'
,
ServerAddress
);
await
updateOption
(
'ServerAddress'
,
ServerAddress
);
};
};
const
submitSMTP
=
async
()
=>
{
const
submitPayAddress
=
async
()
=>
{
if
(
originInputs
[
'SMTPServer'
]
!==
inputs
.
SMTPServer
)
{
if
(
inputs
.
ServerAddress
===
''
)
{
await
updateOption
(
'SMTPServer'
,
inputs
.
SMTPServer
);
showError
(
'请先填写服务器地址'
);
}
return
if
(
originInputs
[
'SMTPAccount'
]
!==
inputs
.
SMTPAccount
)
{
}
await
updateOption
(
'SMTPAccount'
,
inputs
.
SMTPAccount
);
let
PayAddress
=
removeTrailingSlash
(
inputs
.
PayAddress
);
}
await
updateOption
(
'PayAddress'
,
PayAddress
);
if
(
originInputs
[
'SMTPFrom'
]
!==
inputs
.
SMTPFrom
)
{
await
updateOption
(
'EpayId'
,
inputs
.
EpayId
);
await
updateOption
(
'SMTPFrom'
,
inputs
.
SMTPFrom
);
await
updateOption
(
'EpayKey'
,
inputs
.
EpayKey
);
}
await
updateOption
(
'Price'
,
inputs
.
Price
);
if
(
};
originInputs
[
'SMTPPort'
]
!==
inputs
.
SMTPPort
&&
inputs
.
SMTPPort
!==
''
)
{
await
updateOption
(
'SMTPPort'
,
inputs
.
SMTPPort
);
}
if
(
originInputs
[
'SMTPToken'
]
!==
inputs
.
SMTPToken
&&
inputs
.
SMTPToken
!==
''
)
{
await
updateOption
(
'SMTPToken'
,
inputs
.
SMTPToken
);
}
};
const
submitSMTP
=
async
()
=>
{
if
(
originInputs
[
'SMTPServer'
]
!==
inputs
.
SMTPServer
)
{
await
updateOption
(
'SMTPServer'
,
inputs
.
SMTPServer
);
}
if
(
originInputs
[
'SMTPAccount'
]
!==
inputs
.
SMTPAccount
)
{
await
updateOption
(
'SMTPAccount'
,
inputs
.
SMTPAccount
);
}
if
(
originInputs
[
'SMTPFrom'
]
!==
inputs
.
SMTPFrom
)
{
await
updateOption
(
'SMTPFrom'
,
inputs
.
SMTPFrom
);
}
if
(
originInputs
[
'SMTPPort'
]
!==
inputs
.
SMTPPort
&&
inputs
.
SMTPPort
!==
''
)
{
await
updateOption
(
'SMTPPort'
,
inputs
.
SMTPPort
);
}
if
(
originInputs
[
'SMTPToken'
]
!==
inputs
.
SMTPToken
&&
inputs
.
SMTPToken
!==
''
)
{
await
updateOption
(
'SMTPToken'
,
inputs
.
SMTPToken
);
}
};
const
submitEmailDomainWhitelist
=
async
()
=>
{
if
(
originInputs
[
'EmailDomainWhitelist'
]
!==
inputs
.
EmailDomainWhitelist
.
join
(
','
)
&&
inputs
.
SMTPToken
!==
''
)
{
await
updateOption
(
'EmailDomainWhitelist'
,
inputs
.
EmailDomainWhitelist
.
join
(
','
));
}
};
const
submitWeChat
=
async
()
=>
{
const
submitEmailDomainWhitelist
=
async
()
=>
{
if
(
originInputs
[
'WeChatServerAddress'
]
!==
inputs
.
WeChatServerAddress
)
{
if
(
await
updateOption
(
originInputs
[
'EmailDomainWhitelist'
]
!==
inputs
.
EmailDomainWhitelist
.
join
(
','
)
&&
'WeChatServerAddress'
,
inputs
.
SMTPToken
!==
''
removeTrailingSlash
(
inputs
.
WeChatServerAddress
)
)
{
);
await
updateOption
(
'EmailDomainWhitelist'
,
inputs
.
EmailDomainWhitelist
.
join
(
','
));
}
}
if
(
};
originInputs
[
'WeChatAccountQRCodeImageURL'
]
!==
inputs
.
WeChatAccountQRCodeImageURL
)
{
await
updateOption
(
'WeChatAccountQRCodeImageURL'
,
inputs
.
WeChatAccountQRCodeImageURL
);
}
if
(
originInputs
[
'WeChatServerToken'
]
!==
inputs
.
WeChatServerToken
&&
inputs
.
WeChatServerToken
!==
''
)
{
await
updateOption
(
'WeChatServerToken'
,
inputs
.
WeChatServerToken
);
}
};
const
submitGitHubOAuth
=
async
()
=>
{
const
submitWeChat
=
async
()
=>
{
if
(
originInputs
[
'GitHubClientId'
]
!==
inputs
.
GitHubClientId
)
{
if
(
originInputs
[
'WeChatServerAddress'
]
!==
inputs
.
WeChatServerAddress
)
{
await
updateOption
(
'GitHubClientId'
,
inputs
.
GitHubClientId
);
await
updateOption
(
}
'WeChatServerAddress'
,
if
(
removeTrailingSlash
(
inputs
.
WeChatServerAddress
)
originInputs
[
'GitHubClientSecret'
]
!==
inputs
.
GitHubClientSecret
&&
);
inputs
.
GitHubClientSecret
!==
''
}
)
{
if
(
await
updateOption
(
'GitHubClientSecret'
,
inputs
.
GitHubClientSecret
);
originInputs
[
'WeChatAccountQRCodeImageURL'
]
!==
}
inputs
.
WeChatAccountQRCodeImageURL
};
)
{
await
updateOption
(
'WeChatAccountQRCodeImageURL'
,
inputs
.
WeChatAccountQRCodeImageURL
);
}
if
(
originInputs
[
'WeChatServerToken'
]
!==
inputs
.
WeChatServerToken
&&
inputs
.
WeChatServerToken
!==
''
)
{
await
updateOption
(
'WeChatServerToken'
,
inputs
.
WeChatServerToken
);
}
};
const
submitTurnstile
=
async
()
=>
{
const
submitGitHubOAuth
=
async
()
=>
{
if
(
originInputs
[
'TurnstileSiteKey'
]
!==
inputs
.
TurnstileSiteKey
)
{
if
(
originInputs
[
'GitHubClientId'
]
!==
inputs
.
GitHubClientId
)
{
await
updateOption
(
'TurnstileSiteKey'
,
inputs
.
TurnstileSiteKey
);
await
updateOption
(
'GitHubClientId'
,
inputs
.
GitHubClientId
);
}
}
if
(
if
(
originInputs
[
'TurnstileSecretKey'
]
!==
inputs
.
TurnstileSecretKey
&&
originInputs
[
'GitHubClientSecret'
]
!==
inputs
.
GitHubClientSecret
&&
inputs
.
TurnstileSecretKey
!==
''
inputs
.
GitHubClientSecret
!==
''
)
{
)
{
await
updateOption
(
'TurnstileSecretKey'
,
inputs
.
TurnstileSecretKey
);
await
updateOption
(
'GitHubClientSecret'
,
inputs
.
GitHubClientSecret
);
}
}
};
};
const
submitNewRestrictedDomain
=
()
=>
{
const
submitTurnstile
=
async
()
=>
{
const
localDomainList
=
inputs
.
EmailDomainWhitelist
;
if
(
originInputs
[
'TurnstileSiteKey'
]
!==
inputs
.
TurnstileSiteKey
)
{
if
(
restrictedDomainInput
!==
''
&&
!
localDomainList
.
includes
(
restrictedDomainInput
))
{
await
updateOption
(
'TurnstileSiteKey'
,
inputs
.
TurnstileSiteKey
);
setRestrictedDomainInput
(
''
);
}
setInputs
({
if
(
...
inputs
,
originInputs
[
'TurnstileSecretKey'
]
!==
inputs
.
TurnstileSecretKey
&&
EmailDomainWhitelist
:
[...
localDomainList
,
restrictedDomainInput
],
inputs
.
TurnstileSecretKey
!==
''
});
)
{
setEmailDomainWhitelist
([...
EmailDomainWhitelist
,
{
await
updateOption
(
'TurnstileSecretKey'
,
inputs
.
TurnstileSecretKey
);
key
:
restrictedDomainInput
,
}
text
:
restrictedDomainInput
,
};
value
:
restrictedDomainInput
,
}]);
const
submitNewRestrictedDomain
=
()
=>
{
const
localDomainList
=
inputs
.
EmailDomainWhitelist
;
if
(
restrictedDomainInput
!==
''
&&
!
localDomainList
.
includes
(
restrictedDomainInput
))
{
setRestrictedDomainInput
(
''
);
setInputs
({
...
inputs
,
EmailDomainWhitelist
:
[...
localDomainList
,
restrictedDomainInput
],
});
setEmailDomainWhitelist
([...
EmailDomainWhitelist
,
{
key
:
restrictedDomainInput
,
text
:
restrictedDomainInput
,
value
:
restrictedDomainInput
,
}]);
}
}
}
}
return
(
return
(
<
Grid
columns
=
{
1
}
>
<
Grid
columns
=
{
1
}
>
<
Grid
.
Column
>
<
Grid
.
Column
>
<
Form
loading
=
{
loading
}
>
<
Form
loading
=
{
loading
}
>
<
Header
as
=
'h3'
>
通用设置
<
/Header
>
<
Header
as
=
'h3'
>
通用设置
<
/Header
>
<
Form
.
Group
widths
=
'equal'
>
<
Form
.
Group
widths
=
'equal'
>
<
Form
.
Input
<
Form
.
Input
label
=
'服务器地址'
label
=
'服务器地址'
placeholder
=
'例如:https://yourdomain.com'
placeholder
=
'例如:https://yourdomain.com'
value
=
{
inputs
.
ServerAddress
}
value
=
{
inputs
.
ServerAddress
}
name
=
'ServerAddress'
name
=
'ServerAddress'
onChange
=
{
handleInputChange
}
onChange
=
{
handleInputChange
}
/
>
/
>
<
/Form.Group
>
<
/Form.Group
>
<
Form
.
Button
onClick
=
{
submitServerAddress
}
>
<
Form
.
Button
onClick
=
{
submitServerAddress
}
>
更新服务器地址
更新服务器地址
<
/Form.Button
>
<
/Form.Button
>
<
Divider
/>
<
Divider
/>
<
Header
as
=
'h3'
>
配置登录注册
<
/Header
>
<
Header
as
=
'h3'
>
支付设置(当前仅支持易支付接口,使用上方服务器地址作为回调地址!)
<
/Header
>
<
Form
.
Group
inline
>
<
Form
.
Group
widths
=
'equal'
>
<
Form
.
Checkbox
<
Form
.
Input
checked
=
{
inputs
.
PasswordLoginEnabled
===
'true'
}
label
=
'支付地址,不填写则不启用在线支付'
label
=
'允许通过密码进行登录'
placeholder
=
'例如:https://yourdomain.com'
name
=
'PasswordLoginEnabled'
value
=
{
inputs
.
PayAddress
}
onChange
=
{
handleInputChange
}
name
=
'PayAddress'
/
>
onChange
=
{
handleInputChange
}
{
/
>
showPasswordWarningModal
&&
<
Form
.
Input
<
Modal
label
=
'易支付商户ID'
open
=
{
showPasswordWarningModal
}
placeholder
=
'例如:0001'
onClose
=
{()
=>
setShowPasswordWarningModal
(
false
)}
value
=
{
inputs
.
EpayId
}
size
=
{
'tiny'
}
name
=
'EpayId'
style
=
{{
maxWidth
:
'450px'
}}
onChange
=
{
handleInputChange
}
>
/
>
<
Modal
.
Header
>
警告
<
/Modal.Header
>
<
Form
.
Input
<
Modal
.
Content
>
label
=
'易支付商户密钥'
<
p
>
取消密码登录将导致所有未绑定其他登录方式的用户(包括管理员)无法通过密码登录,确认取消?
<
/p
>
placeholder
=
'例如:dejhfueqhujasjmndbjkqaw'
<
/Modal.Content
>
value
=
{
inputs
.
EpayKey
}
<
Modal
.
Actions
>
name
=
'EpayKey'
<
Button
onClick
=
{()
=>
setShowPasswordWarningModal
(
false
)}
>
取消
<
/Button
>
onChange
=
{
handleInputChange
}
<
Button
/
>
color
=
'yellow'
<
Form
.
Input
onClick
=
{
async
()
=>
{
label
=
'充值价格(x元/美金)'
setShowPasswordWarningModal
(
false
);
placeholder
=
'例如:7,就是7元/美金'
await
updateOption
(
'PasswordLoginEnabled'
,
'false'
);
value
=
{
inputs
.
Price
}
}}
name
=
'Price'
>
type
=
'number'
确定
min
=
{
0
}
<
/Button
>
onChange
=
{
handleInputChange
}
<
/Modal.Actions
>
/
>
<
/Modal
>
<
/Form.Group
>
}
<
Form
.
Button
onClick
=
{
submitPayAddress
}
>
<
Form
.
Checkbox
更新支付地址
checked
=
{
inputs
.
PasswordRegisterEnabled
===
'true'
}
<
/Form.Button
>
label
=
'允许通过密码进行注册'
<
Divider
/>
name
=
'PasswordRegisterEnabled'
<
Header
as
=
'h3'
>
配置登录注册
<
/Header
>
onChange
=
{
handleInputChange
}
<
Form
.
Group
inline
>
/
>
<
Form
.
Checkbox
<
Form
.
Checkbox
checked
=
{
inputs
.
PasswordLoginEnabled
===
'true'
}
checked
=
{
inputs
.
EmailVerificationEnabled
===
'true'
}
label
=
'允许通过密码进行登录'
label
=
'通过密码注册时需要进行邮箱验证'
name
=
'PasswordLoginEnabled'
name
=
'EmailVerificationEnabled'
onChange
=
{
handleInputChange
}
onChange
=
{
handleInputChange
}
/
>
/
>
{
<
Form
.
Checkbox
showPasswordWarningModal
&&
checked
=
{
inputs
.
GitHubOAuthEnabled
===
'true'
}
<
Modal
label
=
'允许通过 GitHub 账户登录 & 注册'
open
=
{
showPasswordWarningModal
}
name
=
'GitHubOAuthEnabled'
onClose
=
{()
=>
setShowPasswordWarningModal
(
false
)}
onChange
=
{
handleInputChange
}
size
=
{
'tiny'
}
/
>
style
=
{{
maxWidth
:
'450px'
}}
<
Form
.
Checkbox
>
checked
=
{
inputs
.
WeChatAuthEnabled
===
'true'
}
<
Modal
.
Header
>
警告
<
/Modal.Header
>
label
=
'允许通过微信登录 & 注册'
<
Modal
.
Content
>
name
=
'WeChatAuthEnabled'
<
p
>
取消密码登录将导致所有未绑定其他登录方式的用户(包括管理员)无法通过密码登录,确认取消?
<
/p
>
onChange
=
{
handleInputChange
}
<
/Modal.Content
>
/
>
<
Modal
.
Actions
>
<
/Form.Group
>
<
Button
onClick
=
{()
=>
setShowPasswordWarningModal
(
false
)}
>
取消
<
/Button
>
<
Form
.
Group
inline
>
<
Button
<
Form
.
Checkbox
color
=
'yellow'
checked
=
{
inputs
.
RegisterEnabled
===
'true'
}
onClick
=
{
async
()
=>
{
label
=
'允许新用户注册(此项为否时,新用户将无法以任何方式进行注册)'
setShowPasswordWarningModal
(
false
);
name
=
'RegisterEnabled'
await
updateOption
(
'PasswordLoginEnabled'
,
'false'
);
onChange
=
{
handleInputChange
}
}}
/
>
>
<
Form
.
Checkbox
确定
checked
=
{
inputs
.
TurnstileCheckEnabled
===
'true'
}
<
/Button
>
label
=
'启用 Turnstile 用户校验'
<
/Modal.Actions
>
name
=
'TurnstileCheckEnabled'
<
/Modal
>
onChange
=
{
handleInputChange
}
}
/
>
<
Form
.
Checkbox
<
/Form.Group
>
checked
=
{
inputs
.
PasswordRegisterEnabled
===
'true'
}
<
Divider
/>
label
=
'允许通过密码进行注册'
<
Header
as
=
'h3'
>
name
=
'PasswordRegisterEnabled'
配置邮箱域名白名单
onChange
=
{
handleInputChange
}
<
Header
.
Subheader
>
用以防止恶意用户利用临时邮箱批量注册
<
/Header.Subheader
>
/
>
<
/Header
>
<
Form
.
Checkbox
<
Form
.
Group
widths
=
{
3
}
>
checked
=
{
inputs
.
EmailVerificationEnabled
===
'true'
}
<
Form
.
Checkbox
label
=
'通过密码注册时需要进行邮箱验证'
label
=
'启用邮箱域名白名单'
name
=
'EmailVerificationEnabled'
name
=
'EmailDomainRestrictionEnabled'
onChange
=
{
handleInputChange
}
onChange
=
{
handleInputChange
}
/
>
checked
=
{
inputs
.
EmailDomainRestrictionEnabled
===
'true'
}
<
Form
.
Checkbox
/
>
checked
=
{
inputs
.
GitHubOAuthEnabled
===
'true'
}
<
/Form.Group
>
label
=
'允许通过 GitHub 账户登录 & 注册'
<
Form
.
Group
widths
=
{
2
}
>
name
=
'GitHubOAuthEnabled'
<
Form
.
Dropdown
onChange
=
{
handleInputChange
}
label
=
'允许的邮箱域名'
/
>
placeholder
=
'允许的邮箱域名'
<
Form
.
Checkbox
name
=
'EmailDomainWhitelist'
checked
=
{
inputs
.
WeChatAuthEnabled
===
'true'
}
required
label
=
'允许通过微信登录 & 注册'
fluid
name
=
'WeChatAuthEnabled'
multiple
onChange
=
{
handleInputChange
}
selection
/
>
onChange
=
{
handleInputChange
}
<
/Form.Group
>
value
=
{
inputs
.
EmailDomainWhitelist
}
<
Form
.
Group
inline
>
autoComplete
=
'new-password'
<
Form
.
Checkbox
options
=
{
EmailDomainWhitelist
}
checked
=
{
inputs
.
RegisterEnabled
===
'true'
}
/
>
label
=
'允许新用户注册(此项为否时,新用户将无法以任何方式进行注册)'
<
Form
.
Input
name
=
'RegisterEnabled'
label
=
'添加新的允许的邮箱域名'
onChange
=
{
handleInputChange
}
action
=
{
/
>
<
Button
type
=
'button'
onClick
=
{()
=>
{
<
Form
.
Checkbox
submitNewRestrictedDomain
();
checked
=
{
inputs
.
TurnstileCheckEnabled
===
'true'
}
}}
>
填入
<
/Button
>
label
=
'启用 Turnstile 用户校验'
}
name
=
'TurnstileCheckEnabled'
onKeyDown
=
{(
e
)
=>
{
onChange
=
{
handleInputChange
}
if
(
e
.
key
===
'Enter'
)
{
/
>
submitNewRestrictedDomain
();
<
/Form.Group
>
}
<
Divider
/>
}}
<
Header
as
=
'h3'
>
autoComplete
=
'new-password'
配置邮箱域名白名单
placeholder
=
'输入新的允许的邮箱域名'
<
Header
.
Subheader
>
用以防止恶意用户利用临时邮箱批量注册
<
/Header.Subheader
>
value
=
{
restrictedDomainInput
}
<
/Header
>
onChange
=
{(
e
,
{
value
})
=>
{
<
Form
.
Group
widths
=
{
3
}
>
setRestrictedDomainInput
(
value
);
<
Form
.
Checkbox
}}
label
=
'启用邮箱域名白名单'
/
>
name
=
'EmailDomainRestrictionEnabled'
<
/Form.Group
>
onChange
=
{
handleInputChange
}
<
Form
.
Button
onClick
=
{
submitEmailDomainWhitelist
}
>
保存邮箱域名白名单设置
<
/Form.Button
>
checked
=
{
inputs
.
EmailDomainRestrictionEnabled
===
'true'
}
<
Divider
/>
/
>
<
Header
as
=
'h3'
>
<
/Form.Group
>
配置
SMTP
<
Form
.
Group
widths
=
{
2
}
>
<
Header
.
Subheader
>
用以支持系统的邮件发送
<
/Header.Subheader
>
<
Form
.
Dropdown
<
/Header
>
label
=
'允许的邮箱域名'
<
Form
.
Group
widths
=
{
3
}
>
placeholder
=
'允许的邮箱域名'
<
Form
.
Input
name
=
'EmailDomainWhitelist'
label
=
'SMTP 服务器地址'
required
name
=
'SMTPServer'
fluid
onChange
=
{
handleInputChange
}
multiple
autoComplete
=
'new-password'
selection
value
=
{
inputs
.
SMTPServer
}
onChange
=
{
handleInputChange
}
placeholder
=
'例如:smtp.qq.com'
value
=
{
inputs
.
EmailDomainWhitelist
}
/>
autoComplete
=
'new-password'
<
Form
.
Input
options
=
{
EmailDomainWhitelist
}
label
=
'SMTP 端口'
/
>
name
=
'SMTPPort'
<
Form
.
Input
onChange
=
{
handleInputChange
}
label
=
'添加新的允许的邮箱域名'
autoComplete
=
'new-password'
action
=
{
value
=
{
inputs
.
SMTPPort
}
<
Button
type
=
'button'
onClick
=
{()
=>
{
placeholder
=
'默认: 587'
submitNewRestrictedDomain
();
/>
}}
>
填入
<
/Button
>
<
Form
.
Input
}
label
=
'SMTP 账户'
onKeyDown
=
{(
e
)
=>
{
name
=
'SMTPAccount'
if
(
e
.
key
===
'Enter'
)
{
onChange
=
{
handleInputChange
}
submitNewRestrictedDomain
();
autoComplete
=
'new-password'
}
value
=
{
inputs
.
SMTPAccount
}
}}
placeholder
=
'通常是邮箱地址'
autoComplete
=
'new-password'
/>
placeholder
=
'输入新的允许的邮箱域名'
<
/Form.Group
>
value
=
{
restrictedDomainInput
}
<
Form
.
Group
widths
=
{
3
}
>
onChange
=
{(
e
,
{
value
})
=>
{
<
Form
.
Input
setRestrictedDomainInput
(
value
);
label
=
'SMTP 发送者邮箱'
}}
name
=
'SMTPFrom'
/
>
onChange
=
{
handleInputChange
}
<
/Form.Group
>
autoComplete
=
'new-password'
<
Form
.
Button
onClick
=
{
submitEmailDomainWhitelist
}
>
保存邮箱域名白名单设置
<
/Form.Button
>
value
=
{
inputs
.
SMTPFrom
}
<
Divider
/>
placeholder
=
'通常和邮箱地址保持一致'
<
Header
as
=
'h3'
>
/>
配置
SMTP
<
Form
.
Input
<
Header
.
Subheader
>
用以支持系统的邮件发送
<
/Header.Subheader
>
label
=
'SMTP 访问凭证'
<
/Header
>
name
=
'SMTPToken'
<
Form
.
Group
widths
=
{
3
}
>
onChange
=
{
handleInputChange
}
<
Form
.
Input
type
=
'password'
label
=
'SMTP 服务器地址'
autoComplete
=
'new-password'
name
=
'SMTPServer'
checked
=
{
inputs
.
RegisterEnabled
===
'true'
}
onChange
=
{
handleInputChange
}
placeholder
=
'敏感信息不会发送到前端显示'
autoComplete
=
'new-password'
/>
value
=
{
inputs
.
SMTPServer
}
<
/Form.Group
>
placeholder
=
'例如:smtp.qq.com'
<
Form
.
Button
onClick
=
{
submitSMTP
}
>
保存
SMTP
设置
<
/Form.Button
>
/>
<
Divider
/>
<
Form
.
Input
<
Header
as
=
'h3'
>
label
=
'SMTP 端口'
配置
GitHub
OAuth
App
name
=
'SMTPPort'
<
Header
.
Subheader
>
onChange
=
{
handleInputChange
}
用以支持通过
GitHub
进行登录注册,
autoComplete
=
'new-password'
<
a
href
=
'https://github.com/settings/developers'
target
=
'_blank'
>
value
=
{
inputs
.
SMTPPort
}
点击此处
placeholder
=
'默认: 587'
<
/a
>
/>
管理你的
GitHub
OAuth
App
<
Form
.
Input
<
/Header.Subheader
>
label
=
'SMTP 账户'
<
/Header
>
name
=
'SMTPAccount'
<
Message
>
onChange
=
{
handleInputChange
}
Homepage
URL
填
<
code
>
{
inputs
.
ServerAddress
}
<
/code
>
autoComplete
=
'new-password'
,
Authorization
callback
URL
填
{
' '
}
value
=
{
inputs
.
SMTPAccount
}
<
code
>
{
`
${
inputs
.
ServerAddress
}
/oauth/github`
}
<
/code
>
placeholder
=
'通常是邮箱地址'
<
/Message
>
/>
<
Form
.
Group
widths
=
{
3
}
>
<
/Form.Group
>
<
Form
.
Input
<
Form
.
Group
widths
=
{
3
}
>
label
=
'GitHub Client ID'
<
Form
.
Input
name
=
'GitHubClientId'
label
=
'SMTP 发送者邮箱'
onChange
=
{
handleInputChange
}
name
=
'SMTPFrom'
autoComplete
=
'new-password'
onChange
=
{
handleInputChange
}
value
=
{
inputs
.
GitHubClientId
}
autoComplete
=
'new-password'
placeholder
=
'输入你注册的 GitHub OAuth APP 的 ID'
value
=
{
inputs
.
SMTPFrom
}
/>
placeholder
=
'通常和邮箱地址保持一致'
<
Form
.
Input
/>
label
=
'GitHub Client Secret'
<
Form
.
Input
name
=
'GitHubClientSecret'
label
=
'SMTP 访问凭证'
onChange
=
{
handleInputChange
}
name
=
'SMTPToken'
type
=
'password'
onChange
=
{
handleInputChange
}
autoComplete
=
'new-password'
type
=
'password'
value
=
{
inputs
.
GitHubClientSecret
}
autoComplete
=
'new-password'
placeholder
=
'敏感信息不会发送到前端显示'
checked
=
{
inputs
.
RegisterEnabled
===
'true'
}
/>
placeholder
=
'敏感信息不会发送到前端显示'
<
/Form.Group
>
/>
<
Form
.
Button
onClick
=
{
submitGitHubOAuth
}
>
<
/Form.Group
>
保存
GitHub
OAuth
设置
<
Form
.
Button
onClick
=
{
submitSMTP
}
>
保存
SMTP
设置
<
/Form.Button
>
<
/Form.Button
>
<
Divider
/>
<
Divider
/>
<
Header
as
=
'h3'
>
<
Header
as
=
'h3'
>
配置
GitHub
OAuth
App
配置
WeChat
Server
<
Header
.
Subheader
>
<
Header
.
Subheader
>
用以支持通过
GitHub
进行登录注册,
用以支持通过微信进行登录注册,
<
a
href
=
'https://github.com/settings/developers'
target
=
'_blank'
>
<
a
点击此处
href
=
'https://github.com/songquanpeng/wechat-server'
<
/a
>
target
=
'_blank'
管理你的
GitHub
OAuth
App
>
<
/Header.Subheader
>
点击此处
<
/Header
>
<
/a
>
<
Message
>
了解
WeChat
Server
Homepage
URL
填
<
code
>
{
inputs
.
ServerAddress
}
<
/code
>
<
/Header.Subheader
>
,
Authorization
callback
URL
填
{
' '
}
<
/Header
>
<
code
>
{
`
${
inputs
.
ServerAddress
}
/oauth/github`
}
<
/code
>
<
Form
.
Group
widths
=
{
3
}
>
<
/Message
>
<
Form
.
Input
<
Form
.
Group
widths
=
{
3
}
>
label
=
'WeChat Server 服务器地址'
<
Form
.
Input
name
=
'WeChatServerAddress'
label
=
'GitHub Client ID'
placeholder
=
'例如:https://yourdomain.com'
name
=
'GitHubClientId'
onChange
=
{
handleInputChange
}
onChange
=
{
handleInputChange
}
autoComplete
=
'new-password'
autoComplete
=
'new-password'
value
=
{
inputs
.
WeChatServerAddress
}
value
=
{
inputs
.
GitHubClientId
}
/
>
placeholder
=
'输入你注册的 GitHub OAuth APP 的 ID'
<
Form
.
Input
/>
label
=
'WeChat Server 访问凭证'
<
Form
.
Input
name
=
'WeChatServerToken'
label
=
'GitHub Client Secret'
type
=
'password'
name
=
'GitHubClientSecret'
onChange
=
{
handleInputChange
}
onChange
=
{
handleInputChange
}
autoComplete
=
'new-password'
type
=
'password'
value
=
{
inputs
.
WeChatServerToken
}
autoComplete
=
'new-password'
placeholder
=
'敏感信息不会发送到前端显示'
value
=
{
inputs
.
GitHubClientSecret
}
/>
placeholder
=
'敏感信息不会发送到前端显示'
<
Form
.
Input
/>
label
=
'微信公众号二维码图片链接'
<
/Form.Group
>
name
=
'WeChatAccountQRCodeImageURL'
<
Form
.
Button
onClick
=
{
submitGitHubOAuth
}
>
onChange
=
{
handleInputChange
}
保存
GitHub
OAuth
设置
autoComplete
=
'new-password'
<
/Form.Button
>
value
=
{
inputs
.
WeChatAccountQRCodeImageURL
}
<
Divider
/>
placeholder
=
'输入一个图片链接'
<
Header
as
=
'h3'
>
/>
配置
WeChat
Server
<
/Form.Group
>
<
Header
.
Subheader
>
<
Form
.
Button
onClick
=
{
submitWeChat
}
>
用以支持通过微信进行登录注册,
保存
WeChat
Server
设置
<
a
<
/Form.Button
>
href
=
'https://github.com/songquanpeng/wechat-server'
<
Divider
/>
target
=
'_blank'
<
Header
as
=
'h3'
>
>
配置
Turnstile
点击此处
<
Header
.
Subheader
>
<
/a
>
用以支持用户校验,
了解
WeChat
Server
<
a
href
=
'https://dash.cloudflare.com/'
target
=
'_blank'
>
<
/Header.Subheader
>
点击此处
<
/Header
>
<
/a
>
<
Form
.
Group
widths
=
{
3
}
>
管理你的
Turnstile
Sites
,推荐选择
Invisible
Widget
Type
<
Form
.
Input
<
/Header.Subheader
>
label
=
'WeChat Server 服务器地址'
<
/Header
>
name
=
'WeChatServerAddress'
<
Form
.
Group
widths
=
{
3
}
>
placeholder
=
'例如:https://yourdomain.com'
<
Form
.
Input
onChange
=
{
handleInputChange
}
label
=
'Turnstile Site Key'
autoComplete
=
'new-password'
name
=
'TurnstileSiteKey'
value
=
{
inputs
.
WeChatServerAddress
}
onChange
=
{
handleInputChange
}
/
>
autoComplete
=
'new-password'
<
Form
.
Input
value
=
{
inputs
.
TurnstileSiteKey
}
label
=
'WeChat Server 访问凭证'
placeholder
=
'输入你注册的 Turnstile Site Key'
name
=
'WeChatServerToken'
/>
type
=
'password'
<
Form
.
Input
onChange
=
{
handleInputChange
}
label
=
'Turnstile Secret Key'
autoComplete
=
'new-password'
name
=
'TurnstileSecretKey'
value
=
{
inputs
.
WeChatServerToken
}
onChange
=
{
handleInputChange
}
placeholder
=
'敏感信息不会发送到前端显示'
type
=
'password'
/>
autoComplete
=
'new-password'
<
Form
.
Input
value
=
{
inputs
.
TurnstileSecretKey
}
label
=
'微信公众号二维码图片链接'
placeholder
=
'敏感信息不会发送到前端显示'
name
=
'WeChatAccountQRCodeImageURL'
/>
onChange
=
{
handleInputChange
}
<
/Form.Group
>
autoComplete
=
'new-password'
<
Form
.
Button
onClick
=
{
submitTurnstile
}
>
value
=
{
inputs
.
WeChatAccountQRCodeImageURL
}
保存
Turnstile
设置
placeholder
=
'输入一个图片链接'
<
/Form.Button
>
/>
<
/Form
>
<
/Form.Group
>
<
/Grid.Column
>
<
Form
.
Button
onClick
=
{
submitWeChat
}
>
<
/Grid
>
保存
WeChat
Server
设置
);
<
/Form.Button
>
<
Divider
/>
<
Header
as
=
'h3'
>
配置
Turnstile
<
Header
.
Subheader
>
用以支持用户校验,
<
a
href
=
'https://dash.cloudflare.com/'
target
=
'_blank'
>
点击此处
<
/a
>
管理你的
Turnstile
Sites
,推荐选择
Invisible
Widget
Type
<
/Header.Subheader
>
<
/Header
>
<
Form
.
Group
widths
=
{
3
}
>
<
Form
.
Input
label
=
'Turnstile Site Key'
name
=
'TurnstileSiteKey'
onChange
=
{
handleInputChange
}
autoComplete
=
'new-password'
value
=
{
inputs
.
TurnstileSiteKey
}
placeholder
=
'输入你注册的 Turnstile Site Key'
/>
<
Form
.
Input
label
=
'Turnstile Secret Key'
name
=
'TurnstileSecretKey'
onChange
=
{
handleInputChange
}
type
=
'password'
autoComplete
=
'new-password'
value
=
{
inputs
.
TurnstileSecretKey
}
placeholder
=
'敏感信息不会发送到前端显示'
/>
<
/Form.Group
>
<
Form
.
Button
onClick
=
{
submitTurnstile
}
>
保存
Turnstile
设置
<
/Form.Button
>
<
/Form
>
<
/Grid.Column
>
<
/Grid
>
);
};
};
export
default
SystemSetting
;
export
default
SystemSetting
;
web/src/pages/Home/index.js
View file @
f73ecc57
import
React
,
{
useContext
,
useEffect
,
useState
}
from
'react'
;
import
React
,
{
useContext
,
useEffect
,
useState
}
from
'react'
;
import
{
Card
,
Grid
,
Header
,
Segment
}
from
'semantic-ui-react'
;
import
{
Card
,
Grid
,
Header
,
Segment
}
from
'semantic-ui-react'
;
import
{
API
,
showError
,
showNotice
,
timestamp2string
}
from
'../../helpers'
;
import
{
API
,
showError
,
showNotice
,
timestamp2string
}
from
'../../helpers'
;
import
{
StatusContext
}
from
'../../context/Status'
;
import
{
StatusContext
}
from
'../../context/Status'
;
import
{
marked
}
from
'marked'
;
import
{
marked
}
from
'marked'
;
const
Home
=
()
=>
{
const
Home
=
()
=>
{
const
[
statusState
,
statusDispatch
]
=
useContext
(
StatusContext
);
const
[
statusState
,
statusDispatch
]
=
useContext
(
StatusContext
);
...
@@ -11,11 +11,12 @@ const Home = () => {
...
@@ -11,11 +11,12 @@ const Home = () => {
const
displayNotice
=
async
()
=>
{
const
displayNotice
=
async
()
=>
{
const
res
=
await
API
.
get
(
'/api/notice'
);
const
res
=
await
API
.
get
(
'/api/notice'
);
const
{
success
,
message
,
data
}
=
res
.
data
;
const
{
success
,
message
,
data
}
=
res
.
data
;
if
(
success
)
{
if
(
success
)
{
let
oldNotice
=
localStorage
.
getItem
(
'notice'
);
let
oldNotice
=
localStorage
.
getItem
(
'notice'
);
if
(
data
!==
oldNotice
&&
data
!==
''
)
{
if
(
data
!==
oldNotice
&&
data
!==
''
)
{
showNotice
(
data
);
const
htmlNotice
=
marked
(
data
);
showNotice
(
htmlNotice
,
true
);
localStorage
.
setItem
(
'notice'
,
data
);
localStorage
.
setItem
(
'notice'
,
data
);
}
}
}
else
{
}
else
{
...
@@ -26,7 +27,7 @@ const Home = () => {
...
@@ -26,7 +27,7 @@ const Home = () => {
const
displayHomePageContent
=
async
()
=>
{
const
displayHomePageContent
=
async
()
=>
{
setHomePageContent
(
localStorage
.
getItem
(
'home_page_content'
)
||
''
);
setHomePageContent
(
localStorage
.
getItem
(
'home_page_content'
)
||
''
);
const
res
=
await
API
.
get
(
'/api/home_page_content'
);
const
res
=
await
API
.
get
(
'/api/home_page_content'
);
const
{
success
,
message
,
data
}
=
res
.
data
;
const
{
success
,
message
,
data
}
=
res
.
data
;
if
(
success
)
{
if
(
success
)
{
let
content
=
data
;
let
content
=
data
;
if
(
!
data
.
startsWith
(
'https://'
))
{
if
(
!
data
.
startsWith
(
'https://'
))
{
...
@@ -53,20 +54,28 @@ const Home = () => {
...
@@ -53,20 +54,28 @@ const Home = () => {
return
(
return
(
<>
<>
{
{
// homePageContentLoaded && homePageContent === '' ?
homePageContentLoaded
&&
homePageContent
===
''
?
<>
<>
<
Segment
>
<
Segment
>
<
Header
as
=
'h3'
>
当前状态
<
/Header
>
<
Header
as
=
'h3'
>
系统状况
<
/Header
>
<
Grid
columns
=
{
2
}
stackable
>
<
Grid
columns
=
{
2
}
stackable
>
<
Grid
.
Column
>
<
Grid
.
Column
>
<
Card
fluid
>
<
Card
fluid
>
<
Card
.
Content
>
<
Card
.
Content
>
<
Card
.
Header
>
GPT
-
3.5
<
/Card.Header
>
<
Card
.
Header
>
系统信息
<
/Card.Header
>
<
Card
.
Meta
>
信息总览
<
/Card.Meta
>
<
Card
.
Meta
>
系统
信息总览
<
/Card.Meta
>
<
Card
.
Description
>
<
Card
.
Description
>
<
p
>
通道:官方通道
<
/p
>
<
p
>
名称:
{
statusState
?.
status
?.
system_name
}
<
/p
>
<
p
>
状态:存活
<
/p
>
<
p
>
版本:
{
statusState
?.
status
?.
version
?
statusState
?.
status
?.
version
:
"unknown"
}
<
/p
>
<
p
>
价格:
{
statusState
?.
status
?.
base_price
}
R
&
nbsp
;
/ 刀</
p
>
<
p
>
源码:
<
a
href
=
'https://github.com/songquanpeng/one-api'
target
=
'_blank'
>
https
:
//github.com/songquanpeng/one-api
<
/a
>
<
/p
>
<
p
>
启动时间:
{
getStartTimeString
()}
<
/p
>
<
/Card.Description
>
<
/Card.Description
>
<
/Card.Content
>
<
/Card.Content
>
<
/Card
>
<
/Card
>
...
@@ -74,26 +83,32 @@ const Home = () => {
...
@@ -74,26 +83,32 @@ const Home = () => {
<
Grid
.
Column
>
<
Grid
.
Column
>
<
Card
fluid
>
<
Card
fluid
>
<
Card
.
Content
>
<
Card
.
Content
>
<
Card
.
Header
>
GPT
-
4
<
/Card.Header
>
<
Card
.
Header
>
系统配置
<
/Card.Header
>
<
Card
.
Meta
>
信息
总览
<
/Card.Meta
>
<
Card
.
Meta
>
系统配置
总览
<
/Card.Meta
>
<
Card
.
Description
>
<
Card
.
Description
>
<
p
>
通道:官方通道|低价通道
<
/p
>
<
p
>
<
p
>
状态:
邮箱验证:
{
statusState
?.
status
?.
stable_price
===-
1
?
{
statusState
?.
status
?.
email_verification
===
true
<
span
style
=
{{
color
:
'red'
}}
>
不
&
nbsp
;
&
nbsp
;
&
nbsp
;
可
&
nbsp
;
&
nbsp
;
&
nbsp
;
用
<
/span
>
?
'已启用'
:
:
'未启用'
}
<
span
style
=
{{
color
:
'green'
}}
>
可
&
emsp
;
&
emsp
;
用
<
/span
>
<
/p
>
}
<
p
>
|
GitHub
身份验证:
{
statusState
?.
status
?.
normal_price
===-
1
?
{
statusState
?.
status
?.
github_oauth
===
true
<
span
style
=
{{
color
:
'red'
}}
>
不
&
nbsp
;
&
nbsp
;
&
nbsp
;
可
&
nbsp
;
&
nbsp
;
&
nbsp
;
用
<
/span
>
?
'已启用'
:
:
'未启用'
}
<
span
style
=
{{
color
:
'green'
}}
>
可
&
emsp
;
&
emsp
;
用
<
/span
>
}
<
/p
>
<
/p
>
<
p
>
<
p
>
价格:
{
statusState
?.
status
?.
stable_price
}
R
&
nbsp
;
/ 刀|{statusState
?
.status
?
.normal_price}R /
&
nbsp
;
刀
微信身份验证:
{
statusState
?.
status
?.
wechat_login
===
true
?
'已启用'
:
'未启用'
}
<
/p
>
<
p
>
Turnstile
用户校验:
{
statusState
?.
status
?.
turnstile_check
===
true
?
'已启用'
:
'未启用'
}
<
/p
>
<
/p
>
<
/Card.Description
>
<
/Card.Description
>
<
/Card.Content
>
<
/Card.Content
>
...
@@ -101,21 +116,18 @@ const Home = () => {
...
@@ -101,21 +116,18 @@ const Home = () => {
<
/Grid.Column
>
<
/Grid.Column
>
<
/Grid
>
<
/Grid
>
<
/Segment
>
<
/Segment
>
{
<
/> : <
>
homePageContent
.
startsWith
(
'https://'
)
?
<
iframe
{
src
=
{
homePageContent
}
homePageContent
.
startsWith
(
'https://'
)
?
<
iframe
style
=
{{
width
:
'100%'
,
height
:
'100vh'
,
border
:
'none'
}}
src
=
{
homePageContent
}
/> : <div style={{ fontSize: 'larger' }} dangerouslySetInnerHTML={{ __html: homePageContent }}></
div
>
style
=
{{
width
:
'100%'
,
height
:
'100vh'
,
border
:
'none'
}}
}
/> : <div style={{ fontSize: 'larger' }} dangerouslySetInnerHTML={{ __html: homePageContent }}></
div
>
}
<
/
>
<
/
>
// :
// <>
// </>
}
}
<
/
>
<
/
>
);
);
};
};
export
default
Home
;
export
default
Home
;
\ No newline at end of file
web/src/pages/TopUp/index.js
View file @
f73ecc57
...
@@ -78,9 +78,9 @@ const TopUp = () => {
...
@@ -78,9 +78,9 @@ const TopUp = () => {
form
.
submit
()
form
.
submit
()
document
.
body
.
removeChild
(
form
)
document
.
body
.
removeChild
(
form
)
}
else
{
}
else
{
showError
(
message
);
showError
(
data
);
// setTopUpCount(parseInt(res.data.count));
// setTopUpCount(parseInt(res.data.count));
setAmount
(
parseInt
(
data
));
//
setAmount(parseInt(data));
}
}
}
else
{
}
else
{
showError
(
res
);
showError
(
res
);
...
@@ -160,9 +160,9 @@ const TopUp = () => {
...
@@ -160,9 +160,9 @@ const TopUp = () => {
setRedemptionCode
(
e
.
target
.
value
);
setRedemptionCode
(
e
.
target
.
value
);
}}
}}
/
>
/
>
{
/*<Button color='green' onClick={openTopUpLink}>*/
}
<
Button
color
=
'green'
onClick
=
{
openTopUpLink
}
>
{
/* 获取兑换码*/
}
获取兑换码
{
/*</Button>*/
}
<
/Button
>
<
Button
color
=
'yellow'
onClick
=
{
topUp
}
disabled
=
{
isSubmitting
}
>
<
Button
color
=
'yellow'
onClick
=
{
topUp
}
disabled
=
{
isSubmitting
}
>
{
isSubmitting
?
'兑换中...'
:
'兑换'
}
{
isSubmitting
?
'兑换中...'
:
'兑换'
}
<
/Button
>
<
/Button
>
...
@@ -179,7 +179,7 @@ const TopUp = () => {
...
@@ -179,7 +179,7 @@ const TopUp = () => {
<
/Grid
>
<
/Grid
>
<
/Segment
>
<
/Segment
>
<
Segment
>
<
Segment
>
<
Header
as
=
'h3'
>
在线充值
(最小
10
刀)
<
/Header
>
<
Header
as
=
'h3'
>
在线充值
<
/Header
>
<
Grid
columns
=
{
2
}
stackable
>
<
Grid
columns
=
{
2
}
stackable
>
<
Grid
.
Column
>
<
Grid
.
Column
>
<
Form
>
<
Form
>
...
@@ -194,27 +194,27 @@ const TopUp = () => {
...
@@ -194,27 +194,27 @@ const TopUp = () => {
await
getAmount
(
e
.
target
.
value
);
await
getAmount
(
e
.
target
.
value
);
}}
}}
/
>
/
>
<
Form
.
Input
{
/*<Form.Input*/
}
placeholder
=
'充值码,如果你没有充值码,可不填写'
{
/* placeholder='充值码,如果你没有充值码,可不填写'*/
}
name
=
'redemptionCount'
{
/* name='redemptionCount'*/
}
value
=
{
topUpCode
}
{
/* value={topUpCode}*/
}
onChange
=
{(
e
)
=>
{
{
/* onChange={(e) => {*/
}
setTopUpCode
(
e
.
target
.
value
);
{
/* setTopUpCode(e.target.value);*/
}
}
}
{
/* }}*/
}
/
>
{
/*/>*/
}
<
Button
color
=
'blue'
onClick
=
{
<
Button
color
=
'blue'
onClick
=
{
async
()
=>
{
async
()
=>
{
onlineTopUp
(
'zfb'
)
onlineTopUp
(
'zfb'
)
}
}
}
>
}
>
支付宝
(最大
2000
元)
支付宝
<
/Button
>
<
/Button
>
<
Button
color
=
'green'
onClick
=
{
<
Button
color
=
'green'
onClick
=
{
async
()
=>
{
async
()
=>
{
onlineTopUp
(
'wx'
)
onlineTopUp
(
'wx'
)
}
}
}
>
}
>
微信
(最大
2000
元)
微信
<
/Button
>
<
/Button
>
<
/Form
>
<
/Form
>
<
/Grid.Column
>
<
/Grid.Column
>
...
...
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