Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
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
Unverified
Commit
129f3a2a
authored
Mar 21, 2023
by
archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 账单模块
parent
42c26bd1
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
190 additions
and
37 deletions
+190
-37
src/api/user.ts
+10
-1
src/hooks/usePaging.ts
+60
-0
src/pages/api/user/getBill.ts
+51
-0
src/pages/chat/components/SlideBar.tsx
+2
-2
src/pages/chat/index.tsx
+1
-1
src/pages/number/setting.tsx
+16
-32
src/types/index.d.ts
+9
-1
src/types/mongoSchema.d.ts
+9
-0
src/types/user.d.ts
+9
-0
src/utils/adapt.ts
+15
-0
src/utils/tools.ts
+8
-0
No files found.
src/api/user.ts
View file @
129f3a2a
import
{
GET
,
POST
,
PUT
}
from
'./request'
;
import
{
createHashPassword
}
from
'@/utils/tools'
;
import
{
createHashPassword
,
Obj2Query
}
from
'@/utils/tools'
;
import
{
ResLogin
}
from
'./response/user'
;
import
{
EmailTypeEnum
}
from
'@/constants/common'
;
import
{
UserType
,
UserUpdateParams
}
from
'@/types/user'
;
import
type
{
PagingData
,
RequestPaging
}
from
'@/types'
;
import
{
BillSchema
}
from
'@/types/mongoSchema'
;
import
{
adaptBill
}
from
'@/utils/adapt'
;
export
const
sendCodeToEmail
=
({
email
,
type
}:
{
email
:
string
;
type
:
`
${
EmailTypeEnum
}
`
})
=>
GET
(
'/user/sendEmail'
,
{
email
,
type
});
...
...
@@ -46,3 +49,9 @@ export const postLogin = ({ email, password }: { email: string; password: string
});
export
const
putUserInfo
=
(
data
:
UserUpdateParams
)
=>
PUT
(
'/user/update'
,
data
);
export
const
getUserBills
=
(
data
:
RequestPaging
)
=>
GET
<
PagingData
<
BillSchema
>>
(
`/user/getBill?
${
Obj2Query
(
data
)}
`
).
then
((
res
)
=>
({
...
res
,
data
:
res
.
data
.
map
((
bill
)
=>
adaptBill
(
bill
))
}));
src/hooks/usePaging.ts
0 → 100644
View file @
129f3a2a
import
{
useState
,
useCallback
}
from
'react'
;
import
type
{
PagingData
}
from
'../types/index'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
export
const
usePaging
=
<
T
=
any
>
({
api
,
pageSize
=
10
,
params
}:
{
api
:
(
data
:
any
)
=>
Promise
<
PagingData
<
T
>>
;
pageSize
?:
number
;
params
?:
Record
<
string
,
any
>
;
})
=>
{
const
[
data
,
setData
]
=
useState
<
T
[]
>
([]);
const
[
pageNum
,
setPageNum
]
=
useState
(
1
);
const
[
total
,
setTotal
]
=
useState
(
0
);
const
[
isLoadAll
,
setIsLoadAll
]
=
useState
(
false
);
const
[
requesting
,
setRequesting
]
=
useState
(
false
);
const
getData
=
useCallback
(
async
(
init
=
false
)
=>
{
if
(
requesting
)
return
;
if
(
!
init
&&
isLoadAll
)
return
;
setRequesting
(
true
);
try
{
const
res
=
await
api
({
pageNum
,
pageSize
,
...(
params
?
params
:
{})
});
setData
((
state
)
=>
{
const
data
=
init
?
res
.
data
:
state
.
concat
(
res
.
data
);
if
(
data
.
length
>=
res
.
total
)
{
setIsLoadAll
(
true
);
}
return
data
;
});
setTotal
(
res
.
total
);
}
catch
(
error
)
{
console
.
log
(
error
);
}
setRequesting
(
false
);
return
null
;
},
[
api
,
isLoadAll
,
pageNum
,
pageSize
,
params
,
requesting
]
);
useQuery
([
'init'
,
pageNum
],
()
=>
getData
(
pageNum
===
1
));
return
{
pageNum
,
pageSize
,
setPageNum
,
total
,
data
,
getData
};
};
src/pages/api/user/getBill.ts
0 → 100644
View file @
129f3a2a
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import
type
{
NextApiRequest
,
NextApiResponse
}
from
'next'
;
import
{
jsonRes
}
from
'@/service/response'
;
import
{
connectToDatabase
,
Bill
}
from
'@/service/mongo'
;
import
{
authToken
}
from
'@/service/utils/tools'
;
import
type
{
BillSchema
}
from
'@/types/mongoSchema'
;
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
try
{
const
{
authorization
}
=
req
.
headers
;
let
{
pageNum
=
1
,
pageSize
=
10
}
=
req
.
query
as
{
pageNum
:
string
;
pageSize
:
string
};
pageNum
=
+
pageNum
;
pageSize
=
+
pageSize
;
if
(
!
authorization
)
{
throw
new
Error
(
'缺少登录凭证'
);
}
const
userId
=
await
authToken
(
authorization
);
await
connectToDatabase
();
// 根据 id 获取用户账单
const
bills
=
await
Bill
.
find
<
BillSchema
>
({
userId
})
.
sort
({
createdAt
:
-
1
})
// 按照创建时间倒序排列
.
skip
((
pageNum
-
1
)
*
pageSize
)
.
limit
(
pageSize
);
// 获取total
const
total
=
await
Bill
.
countDocuments
({
userId
});
jsonRes
(
res
,
{
data
:
{
pageNum
,
pageSize
,
data
:
bills
,
total
}
});
}
catch
(
err
)
{
jsonRes
(
res
,
{
code
:
500
,
error
:
err
});
}
}
src/pages/chat/components/SlideBar.tsx
View file @
129f3a2a
...
...
@@ -85,7 +85,7 @@ const SlideBar = ({
:
{})}
onClick=
{
()
=>
{
if
(
item
.
chatId
===
chatId
)
return
;
router
.
push
(
`/chat?chatId=${item.chatId}`
);
router
.
replace
(
`/chat?chatId=${item.chatId}`
);
onClose
();
}
}
>
...
...
@@ -187,7 +187,7 @@ const SlideBar = ({
:
{})}
onClick=
{
async
()
=>
{
if
(
item
.
name
===
name
)
return
;
router
.
push
(
`/chat?chatId=${await getChatSiteId(item._id)}`
);
router
.
replace
(
`/chat?chatId=${await getChatSiteId(item._id)}`
);
onClose
();
}
}
>
...
...
src/pages/chat/index.tsx
View file @
129f3a2a
...
...
@@ -152,7 +152,7 @@ const Chat = ({ chatId }: { chatId: string }) => {
const
resetChat
=
useCallback
(
async
()
=>
{
if
(
!
chatData
)
return
;
try
{
router
.
push
(
`/chat?chatId=
${
await
getChatSiteId
(
chatData
.
modelId
)}
`
);
router
.
replace
(
`/chat?chatId=
${
await
getChatSiteId
(
chatData
.
modelId
)}
`
);
}
catch
(
error
:
any
)
{
toast
({
title
:
error
?.
message
||
'生成新对话失败'
,
...
...
src/pages/number/setting.tsx
View file @
129f3a2a
...
...
@@ -18,11 +18,13 @@ import {
import
{
DeleteIcon
}
from
'@chakra-ui/icons'
;
import
{
useForm
,
useFieldArray
}
from
'react-hook-form'
;
import
{
UserUpdateParams
}
from
'@/types/user'
;
import
{
putUserInfo
}
from
'@/api/user'
;
import
{
putUserInfo
,
getUserBills
}
from
'@/api/user'
;
import
{
useToast
}
from
'@/hooks/useToast'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
{
useUserStore
}
from
'@/store/user'
;
import
{
UserType
}
from
'@/types/user'
;
import
{
usePaging
}
from
'@/hooks/usePaging'
;
import
type
{
UserBillType
}
from
'@/types/user'
;
const
NumberSetting
=
()
=>
{
const
{
userInfo
,
updateUserInfo
}
=
useUserStore
();
...
...
@@ -39,7 +41,11 @@ const NumberSetting = () => {
control
,
name
:
'accounts'
});
const
{
setPageNum
,
data
:
bills
}
=
usePaging
<
UserBillType
>
({
api
:
getUserBills
,
pageSize
:
20
});
console
.
log
(
bills
);
const
onclickSave
=
useCallback
(
async
(
data
:
UserUpdateParams
)
=>
{
setLoading
(
true
);
...
...
@@ -156,41 +162,19 @@ const NumberSetting = () => {
<
Table
>
<
Thead
>
<
Tr
>
<
Th
>
账号类型
</
Th
>
<
Th
>
值
</
Th
>
<
Th
></
Th
>
<
Th
>
时间
</
Th
>
<
Th
>
内容长度
</
Th
>
<
Th
>
消费
</
Th
>
</
Tr
>
</
Thead
>
<
Tbody
>
{
accounts
.
map
((
item
,
i
)
=>
(
<
Tbody
fontSize=
{
'sm'
}
>
{
bills
.
map
((
item
)
=>
(
<
Tr
key=
{
item
.
id
}
>
<
Td
minW=
{
'200px'
}
>
<
Select
{
...
register
(`
accounts
.
$
{
i
}
.
type
`,
{
required
:
'类型不能为空'
})}
>
<
option
value=
"openai"
>
openai
</
option
>
</
Select
>
</
Td
>
<
Td
minW=
{
'200px'
}
>
{
item
.
time
}
</
Td
>
<
Td
minW=
{
'200px'
}
whiteSpace=
"pre-wrap"
wordBreak=
{
'break-all'
}
>
<
Input
{
...
register
(`
accounts
.
$
{
i
}
.
value
`,
{
required
:
'账号不能为空'
})}
></
Input
>
</
Td
>
<
Td
>
<
IconButton
aria
-
label=
"删除账号"
icon=
{
<
DeleteIcon
/>
}
colorScheme=
{
'red'
}
onClick=
{
()
=>
{
removeAccount
(
i
);
handleSubmit
(
onclickSave
)();
}
}
/>
{
item
.
textLen
}
</
Td
>
<
Td
>
{
item
.
price
}
元
</
Td
>
</
Tr
>
))
}
</
Tbody
>
...
...
src/types/index.d.ts
View file @
129f3a2a
...
...
@@ -3,4 +3,12 @@ import type { Mongoose } from 'mongoose';
declare
global
{
var
mongodb
:
Mongoose
|
string
|
null
;
}
export
{};
export
type
PagingData
<
T
>
=
{
pageNum
;
pageSize
;
data
:
T
[];
total
;
};
export
type
RequestPaging
=
{
pageNum
:
number
;
pageSize
:
number
};
src/types/mongoSchema.d.ts
View file @
129f3a2a
...
...
@@ -75,3 +75,12 @@ export interface ChatPopulate extends ChatSchema {
userId
:
UserModelSchema
;
modelId
:
ModelSchema
;
}
export
interface
BillSchema
{
_id
:
string
;
userId
:
string
;
chatId
:
string
;
time
:
number
;
textLen
:
number
;
price
:
number
;
}
src/types/user.d.ts
View file @
129f3a2a
...
...
@@ -19,3 +19,12 @@ export interface UserUpdateParams {
value
:
string
;
}[];
}
export
interface
UserBillType
{
id
:
string
;
time
:
string
;
textLen
:
number
;
userId
:
string
;
chatId
:
string
;
price
:
number
;
}
src/utils/adapt.ts
0 → 100644
View file @
129f3a2a
import
{
formatPrice
}
from
'./user'
;
import
dayjs
from
'dayjs'
;
import
type
{
BillSchema
}
from
'../types/mongoSchema'
;
import
type
{
UserBillType
}
from
'@/types/user'
;
export
const
adaptBill
=
(
bill
:
BillSchema
):
UserBillType
=>
{
return
{
id
:
bill
.
_id
,
userId
:
bill
.
userId
,
chatId
:
bill
.
chatId
,
time
:
dayjs
(
bill
.
time
).
format
(
'YYYY/MM/DD hh:mm:ss'
),
textLen
:
bill
.
textLen
,
price
:
formatPrice
(
bill
.
price
)
};
};
src/utils/tools.ts
View file @
129f3a2a
...
...
@@ -41,6 +41,14 @@ export const createHashPassword = (text: string) => {
return
hash
;
};
export
const
Obj2Query
=
(
obj
:
Record
<
string
,
string
|
number
>
)
=>
{
const
queryParams
=
new
URLSearchParams
();
for
(
const
key
in
obj
)
{
queryParams
.
append
(
key
,
`
${
obj
[
key
]}
`
);
}
return
queryParams
.
toString
();
};
/**
* 读取文件内容
*/
...
...
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