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
4c1a23d6
authored
Nov 10, 2023
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
完善兑换码界面
parent
78e05b8e
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
136 additions
and
63 deletions
+136
-63
controller/token.go
+2
-1
model/token.go
+6
-2
web/src/components/RedemptionsTable.js
+0
-0
web/src/components/TokensTable.js
+13
-3
web/src/pages/Redemption/EditRedemption.js
+99
-46
web/src/pages/Redemption/index.js
+10
-4
web/src/pages/Token/EditToken.js
+2
-2
web/src/pages/Token/index.js
+4
-5
No files found.
controller/token.go
View file @
4c1a23d6
...
...
@@ -39,7 +39,8 @@ func GetAllTokens(c *gin.Context) {
func
SearchTokens
(
c
*
gin
.
Context
)
{
userId
:=
c
.
GetInt
(
"id"
)
keyword
:=
c
.
Query
(
"keyword"
)
tokens
,
err
:=
model
.
SearchUserTokens
(
userId
,
keyword
)
token
:=
c
.
Query
(
"token"
)
tokens
,
err
:=
model
.
SearchUserTokens
(
userId
,
keyword
,
token
)
if
err
!=
nil
{
c
.
JSON
(
http
.
StatusOK
,
gin
.
H
{
"success"
:
false
,
...
...
model/token.go
View file @
4c1a23d6
...
...
@@ -5,6 +5,7 @@ import (
"fmt"
"gorm.io/gorm"
"one-api/common"
"strings"
)
type
Token
struct
{
...
...
@@ -28,8 +29,11 @@ func GetAllUserTokens(userId int, startIdx int, num int) ([]*Token, error) {
return
tokens
,
err
}
func
SearchUserTokens
(
userId
int
,
keyword
string
)
(
tokens
[]
*
Token
,
err
error
)
{
err
=
DB
.
Where
(
"user_id = ?"
,
userId
)
.
Where
(
"name LIKE ?"
,
keyword
+
"%"
)
.
Find
(
&
tokens
)
.
Error
func
SearchUserTokens
(
userId
int
,
keyword
string
,
token
string
)
(
tokens
[]
*
Token
,
err
error
)
{
if
token
!=
""
{
token
=
strings
.
Trim
(
token
,
"sk-"
)
}
err
=
DB
.
Where
(
"user_id = ?"
,
userId
)
.
Where
(
"name LIKE ? or key LIKE ?"
,
keyword
+
"%"
,
token
+
"%"
)
.
Find
(
&
tokens
)
.
Error
return
tokens
,
err
}
...
...
web/src/components/RedemptionsTable.js
View file @
4c1a23d6
This diff is collapsed.
Click to expand it.
web/src/components/TokensTable.js
View file @
4c1a23d6
...
...
@@ -179,6 +179,7 @@ const TokensTable = () => {
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
activePage
,
setActivePage
]
=
useState
(
1
);
const
[
searchKeyword
,
setSearchKeyword
]
=
useState
(
''
);
const
[
searchToken
,
setSearchToken
]
=
useState
(
''
);
const
[
searching
,
setSearching
]
=
useState
(
false
);
const
[
showTopUpModal
,
setShowTopUpModal
]
=
useState
(
false
);
const
[
targetTokenIdx
,
setTargetTokenIdx
]
=
useState
(
0
);
...
...
@@ -188,9 +189,6 @@ const TokensTable = () => {
const
closeEdit
=
()
=>
{
setShowEdit
(
false
);
// setEditingToken({
// id: undefined,
// });
}
const
setTokensFormat
=
(
tokens
)
=>
{
...
...
@@ -401,6 +399,10 @@ const TokensTable = () => {
setSearchKeyword
(
value
.
trim
());
};
const
handleSearchTokenChange
=
async
(
value
)
=>
{
setSearchToken
(
value
.
trim
());
};
const
sortToken
=
(
key
)
=>
{
if
(
tokens
.
length
===
0
)
return
;
setLoading
(
true
);
...
...
@@ -447,6 +449,14 @@ const TokensTable = () => {
loading
=
{
searching
}
onChange
=
{
handleKeywordChange
}
/
>
<
Form
.
Input
field
=
"token"
label
=
'Key'
placeholder
=
'密钥'
value
=
{
searchToken
}
loading
=
{
searching
}
onChange
=
{
handleSearchTokenChange
}
/
>
<
Button
label
=
'查询'
type
=
"primary"
htmlType
=
"submit"
className
=
"btn-margin-right"
onClick
=
{
searchTokens
}
style
=
{{
marginRight
:
8
}}
>
查询
<
/Button
>
<
/Form
>
...
...
web/src/pages/Redemption/EditRedemption.js
View file @
4c1a23d6
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Button
,
Form
,
Header
,
Segment
}
from
'semantic-ui-react'
;
import
{
useParams
,
useNavigate
}
from
'react-router-dom'
;
import
{
API
,
downloadTextAsFile
,
showError
,
showSuccess
}
from
'../../helpers'
;
import
{
API
,
downloadTextAsFile
,
isMobile
,
showError
,
showSuccess
}
from
'../../helpers'
;
import
{
renderQuota
,
renderQuotaWithPrompt
}
from
'../../helpers/render'
;
import
{
SideSheet
,
Space
,
Spin
,
Button
,
Input
,
Typography
,
AutoComplete
,
Modal
}
from
"@douyinfe/semi-ui"
;
import
Title
from
"@douyinfe/semi-ui/lib/es/typography/title"
;
import
{
Divider
}
from
"semantic-ui-react"
;
const
EditRedemption
=
()
=>
{
const
params
=
useParams
();
const
navigate
=
useNavigate
();
const
redemptionId
=
params
.
id
;
const
isEdit
=
redemptionId
!==
undefined
;
const
EditRedemption
=
(
props
)
=>
{
const
isEdit
=
props
.
editingRedemption
.
id
!==
undefined
;
const
[
loading
,
setLoading
]
=
useState
(
isEdit
);
const
params
=
useParams
();
const
navigate
=
useNavigate
()
const
originInputs
=
{
name
:
''
,
quota
:
100000
,
...
...
@@ -19,15 +21,16 @@ const EditRedemption = () => {
const
{
name
,
quota
,
count
}
=
inputs
;
const
handleCancel
=
()
=>
{
navigate
(
'/redemption'
);
}
;
props
.
handleClose
(
);
}
const
handleInputChange
=
(
e
,
{
name
,
value
}
)
=>
{
const
handleInputChange
=
(
name
,
value
)
=>
{
setInputs
((
inputs
)
=>
({
...
inputs
,
[
name
]:
value
}));
};
const
loadRedemption
=
async
()
=>
{
let
res
=
await
API
.
get
(
`/api/redemption/
${
redemptionId
}
`
);
setLoading
(
true
);
let
res
=
await
API
.
get
(
`/api/redemption/
${
props
.
editingRedemption
.
id
}
`
);
const
{
success
,
message
,
data
}
=
res
.
data
;
if
(
success
)
{
setInputs
(
data
);
...
...
@@ -36,20 +39,28 @@ const EditRedemption = () => {
}
setLoading
(
false
);
};
useEffect
(()
=>
{
if
(
isEdit
)
{
loadRedemption
().
then
();
loadRedemption
().
then
(
()
=>
{
// console.log(inputs);
}
);
}
else
{
setInputs
(
originInputs
);
}
},
[]);
},
[
props
.
editingRedemption
.
id
]);
const
submit
=
async
()
=>
{
if
(
!
isEdit
&&
inputs
.
name
===
''
)
return
;
setLoading
(
true
);
let
localInputs
=
inputs
;
localInputs
.
count
=
parseInt
(
localInputs
.
count
);
localInputs
.
quota
=
parseInt
(
localInputs
.
quota
);
let
res
;
if
(
isEdit
)
{
res
=
await
API
.
put
(
`/api/redemption/`
,
{
...
localInputs
,
id
:
parseInt
(
redemptionI
d
)
});
res
=
await
API
.
put
(
`/api/redemption/`
,
{
...
localInputs
,
id
:
parseInt
(
props
.
editingRedemption
.
i
d
)
});
}
else
{
res
=
await
API
.
post
(
`/api/redemption/`
,
{
...
localInputs
...
...
@@ -59,9 +70,13 @@ const EditRedemption = () => {
if
(
success
)
{
if
(
isEdit
)
{
showSuccess
(
'兑换码更新成功!'
);
props
.
refresh
();
props
.
handleClose
();
}
else
{
showSuccess
(
'兑换码创建成功!'
);
setInputs
(
originInputs
);
props
.
refresh
();
props
.
handleClose
();
}
}
else
{
showError
(
message
);
...
...
@@ -71,56 +86,94 @@ const EditRedemption = () => {
for
(
let
i
=
0
;
i
<
data
.
length
;
i
++
)
{
text
+=
data
[
i
]
+
"\n"
;
}
downloadTextAsFile
(
text
,
`
${
inputs
.
name
}
.txt`
);
// downloadTextAsFile(text, `${inputs.name}.txt`);
Modal
.
confirm
({
title
:
'兑换码创建成功'
,
content
:
(
<
div
>
<
p
>
兑换码创建成功,是否下载兑换码?
<
/p
>
<
p
>
兑换码将以文本文件的形式下载,文件名为兑换码的名称。
<
/p
>
<
/div
>
),
onOk
:
()
=>
{
downloadTextAsFile
(
text
,
`
${
inputs
.
name
}
.txt`
);
}
});
}
setLoading
(
false
);
};
return
(
<>
<
Segment
loading
=
{
loading
}
>
<
Header
as
=
'h3'
>
{
isEdit
?
'更新兑换码信息'
:
'创建新的兑换码'
}
<
/Header
>
<
Form
autoComplete
=
'new-password'
>
<
Form
.
Field
>
<
Form
.
Input
<
SideSheet
placement
=
{
isEdit
?
'right'
:
'left'
}
title
=
{
<
Title
level
=
{
3
}
>
{
isEdit
?
'更新兑换码信息'
:
'创建新的兑换码'
}
<
/Title>
}
headerStyle
=
{{
borderBottom
:
'1px solid var(--semi-color-border)'
}}
bodyStyle
=
{{
borderBottom
:
'1px solid var(--semi-color-border)'
}}
visible
=
{
props
.
visiable
}
footer
=
{
<
div
style
=
{{
display
:
'flex'
,
justifyContent
:
'flex-end'
}}
>
<
Space
>
<
Button
theme
=
'solid'
size
=
{
'large'
}
onClick
=
{
submit
}
>
提交
<
/Button
>
<
Button
theme
=
'solid'
size
=
{
'large'
}
type
=
{
'tertiary'
}
onClick
=
{
handleCancel
}
>
取消
<
/Button
>
<
/Space
>
<
/div
>
}
closeIcon
=
{
null
}
onCancel
=
{()
=>
handleCancel
()}
width
=
{
isMobile
()
?
'100%'
:
600
}
>
<
Spin
spinning
=
{
loading
}
>
<
Input
style
=
{{
marginTop
:
20
}}
label
=
'名称'
name
=
'name'
placeholder
=
{
'请输入名称'
}
onChange
=
{
handleInputChange
}
onChange
=
{
value
=>
handleInputChange
(
'name'
,
value
)
}
value
=
{
name
}
autoComplete
=
'new-password'
required
=
{
!
isEdit
}
/
>
<
/Form.Field
>
<
Form
.
Field
>
<
Form
.
Input
label
=
{
`额度
${
renderQuotaWithPrompt
(
quota
)}
`
}
/
>
<
Divider
/>
<
div
style
=
{{
marginTop
:
20
}}
>
<
Typography
.
Text
>
{
`额度
${
renderQuotaWithPrompt
(
quota
)}
`
}
<
/Typography.Text
>
<
/div
>
<
AutoComplete
style
=
{{
marginTop
:
8
}}
name
=
'quota'
placeholder
=
{
'请输入
单个兑换码中包含的
额度'
}
onChange
=
{
handleInputChange
}
placeholder
=
{
'请输入额度'
}
onChange
=
{
(
value
)
=>
handleInputChange
(
'quota'
,
value
)
}
value
=
{
quota
}
autoComplete
=
'new-password'
type
=
'number'
/>
<
/Form.Field
>
position
=
{
'bottom'
}
data
=
{[
{
value
:
500000
,
label
:
'1$'
},
{
value
:
5000000
,
label
:
'10$'
},
{
value
:
25000000
,
label
:
'50$'
},
{
value
:
50000000
,
label
:
'100$'
},
{
value
:
250000000
,
label
:
'500$'
},
{
value
:
500000000
,
label
:
'1000$'
},
]}
/
>
{
!
isEdit
&&
<>
<
Form
.
Field
>
<
Form
.
Input
label
=
'生成数量'
name
=
'count'
placeholder
=
{
'请输入生成数量'
}
onChange
=
{
handleInputChange
}
value
=
{
count
}
autoComplete
=
'new-password'
type
=
'number'
!
isEdit
&&
<>
<
Divider
/>
<
Typography
.
Text
>
生成数量
<
/Typography.Text
>
<
Input
style
=
{{
marginTop
:
8
}}
label
=
'生成数量'
name
=
'count'
placeholder
=
{
'请输入生成数量'
}
onChange
=
{
value
=>
handleInputChange
(
'count'
,
value
)}
value
=
{
count
}
autoComplete
=
'new-password'
type
=
'number'
/>
<
/Form.Field
>
<
/
>
<
/
>
}
<
Button
positive
onClick
=
{
submit
}
>
提交
<
/Button
>
<
Button
onClick
=
{
handleCancel
}
>
取消
<
/Button
>
<
/Form
>
<
/Segment
>
<
/Spin
>
<
/SideSheet
>
<
/
>
);
};
...
...
web/src/pages/Redemption/index.js
View file @
4c1a23d6
import
React
from
'react'
;
import
{
Segment
,
Header
}
from
'semantic-ui-react'
;
import
RedemptionsTable
from
'../../components/RedemptionsTable'
;
import
TokensTable
from
"../../components/TokensTable"
;
import
{
Layout
}
from
"@douyinfe/semi-ui"
;
const
Redemption
=
()
=>
(
<>
<
Segment
>
<
Header
as
=
'h3'
>
管理兑换码
<
/Header
>
<
RedemptionsTable
/>
<
/Segment
>
<
Layout
>
<
Layout
.
Header
>
<
h3
>
管理兑换码
<
/h3
>
<
/Layout.Header
>
<
Layout
.
Content
>
<
RedemptionsTable
/>
<
/Layout.Content
>
<
/Layout
>
<
/
>
);
...
...
web/src/pages/Token/EditToken.js
View file @
4c1a23d6
...
...
@@ -63,7 +63,7 @@ const EditToken = (props) => {
if
(
isEdit
)
{
loadToken
().
then
(
()
=>
{
console
.
log
(
inputs
);
//
console.log(inputs);
}
);
}
else
{
...
...
@@ -72,8 +72,8 @@ const EditToken = (props) => {
},
[
props
.
editingToken
.
id
]);
const
submit
=
async
()
=>
{
setLoading
(
true
);
if
(
!
isEdit
&&
inputs
.
name
===
''
)
return
;
setLoading
(
true
);
let
localInputs
=
inputs
;
localInputs
.
remain_quota
=
parseInt
(
localInputs
.
remain_quota
);
if
(
localInputs
.
expired_time
!==
-
1
)
{
...
...
web/src/pages/Token/index.js
View file @
4c1a23d6
import
React
from
'react'
;
import
TokensTable
from
'../../components/TokensTable'
;
import
{
Layout
}
from
"@douyinfe/semi-ui"
;
const
{
Content
,
Header
}
=
Layout
;
const
Token
=
()
=>
(
<>
<
Layout
>
<
Header
>
<
Layout
.
Header
>
<
h3
>
我的令牌
<
/h3
>
<
/Header
>
<
Content
>
<
/
Layout.
Header
>
<
Layout
.
Content
>
<
TokensTable
/>
<
/Content
>
<
/
Layout.
Content
>
<
/Layout
>
<
/
>
);
...
...
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