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
1367ba9d
authored
Jun 27, 2023
by
archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: admin
parent
62489ef1
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
110 additions
and
29 deletions
+110
-29
admin/service/route/kb.js
+0
-1
admin/service/route/user.js
+50
-3
admin/src/Dashboard.tsx
+60
-25
No files found.
admin/service/route/kb.js
View file @
1367ba9d
...
@@ -24,7 +24,6 @@ export const useKbRoute = (app) => {
...
@@ -24,7 +24,6 @@ export const useKbRoute = (app) => {
}
}
:
{})
:
{})
};
};
console
.
log
(
where
);
const
kbsRaw
=
await
Kb
.
find
(
where
)
const
kbsRaw
=
await
Kb
.
find
(
where
)
.
skip
(
start
)
.
skip
(
start
)
...
...
admin/service/route/user.js
View file @
1367ba9d
...
@@ -8,11 +8,12 @@ const hashPassword = (psw) => {
...
@@ -8,11 +8,12 @@ const hashPassword = (psw) => {
return
crypto
.
createHash
(
'sha256'
).
update
(
psw
).
digest
(
'hex'
);
return
crypto
.
createHash
(
'sha256'
).
update
(
psw
).
digest
(
'hex'
);
};
};
const
day
=
60
;
export
const
useUserRoute
=
(
app
)
=>
{
export
const
useUserRoute
=
(
app
)
=>
{
// 统计近 30 天注册用户数量
// 统计近 30 天注册用户数量
app
.
get
(
'/users/data'
,
auth
(),
async
(
req
,
res
)
=>
{
app
.
get
(
'/users/data'
,
auth
(),
async
(
req
,
res
)
=>
{
try
{
try
{
const
day
=
60
;
let
startCount
=
await
User
.
countDocuments
({
let
startCount
=
await
User
.
countDocuments
({
createTime
:
{
$lt
:
new
Date
(
Date
.
now
()
-
day
*
24
*
60
*
60
*
1000
)
}
createTime
:
{
$lt
:
new
Date
(
Date
.
now
()
-
day
*
24
*
60
*
60
*
1000
)
}
});
});
...
@@ -92,7 +93,6 @@ export const useUserRoute = (app) => {
...
@@ -92,7 +93,6 @@ export const useUserRoute = (app) => {
res
.
status
(
500
).
json
({
error
:
'Error fetching users'
});
res
.
status
(
500
).
json
({
error
:
'Error fetching users'
});
}
}
});
});
// 创建用户
// 创建用户
app
.
post
(
'/users'
,
auth
(),
async
(
req
,
res
)
=>
{
app
.
post
(
'/users'
,
auth
(),
async
(
req
,
res
)
=>
{
try
{
try
{
...
@@ -134,7 +134,6 @@ export const useUserRoute = (app) => {
...
@@ -134,7 +134,6 @@ export const useUserRoute = (app) => {
res
.
status
(
500
).
json
({
error
:
'Error updating user'
});
res
.
status
(
500
).
json
({
error
:
'Error updating user'
});
}
}
});
});
// 新增: 获取 pays 列表
// 新增: 获取 pays 列表
app
.
get
(
'/pays'
,
auth
(),
async
(
req
,
res
)
=>
{
app
.
get
(
'/pays'
,
auth
(),
async
(
req
,
res
)
=>
{
try
{
try
{
...
@@ -179,4 +178,52 @@ export const useUserRoute = (app) => {
...
@@ -179,4 +178,52 @@ export const useUserRoute = (app) => {
res
.
status
(
500
).
json
({
error
:
'Error fetching pays'
,
details
:
err
.
message
});
res
.
status
(
500
).
json
({
error
:
'Error fetching pays'
,
details
:
err
.
message
});
}
}
});
});
// 获取本月账单
app
.
get
(
'/pays/data'
,
auth
(),
async
(
req
,
res
)
=>
{
try
{
let
startCount
=
0
;
const
paysRaw
=
await
Pay
.
aggregate
([
{
$match
:
{
status
:
'SUCCESS'
,
createTime
:
{
$gte
:
new
Date
(
Date
.
now
()
-
day
*
24
*
60
*
60
*
1000
)
}
}
},
{
$group
:
{
_id
:
{
year
:
{
$year
:
'$createTime'
},
month
:
{
$month
:
'$createTime'
},
day
:
{
$dayOfMonth
:
'$createTime'
}
},
count
:
{
$sum
:
'$price'
}
}
},
{
$project
:
{
_id
:
0
,
date
:
{
$dateFromParts
:
{
year
:
'$_id.year'
,
month
:
'$_id.month'
,
day
:
'$_id.day'
}
},
count
:
1
}
},
{
$sort
:
{
date
:
1
}
}
]);
const
countResult
=
paysRaw
.
map
((
item
)
=>
{
startCount
+=
item
.
count
;
return
{
date
:
item
.
date
,
count
:
startCount
};
});
res
.
json
(
countResult
);
}
catch
(
err
)
{
console
.
log
(
`Error fetching users:
${
err
}
`
);
res
.
status
(
500
).
json
({
error
:
'Error fetching users'
});
}
});
};
};
admin/src/Dashboard.tsx
View file @
1367ba9d
...
@@ -14,14 +14,24 @@ import {
...
@@ -14,14 +14,24 @@ import {
import
dayjs
from
'dayjs'
;
import
dayjs
from
'dayjs'
;
const
authStorageKey
=
'tushan:auth'
;
const
authStorageKey
=
'tushan:auth'
;
const
PRICE_SCALE
=
100000
;
type
UsersChartDataType
=
{
count
:
number
;
date
:
string
;
increase
:
number
;
increaseRate
:
string
};
type
fetchChatData
=
{
count
:
number
;
date
:
string
;
increase
?:
number
;
increaseRate
?:
string
};
type
chatDataType
=
{
date
:
string
;
userCount
:
number
;
userIncrease
?:
number
;
userIncreaseRate
?:
string
;
payCount
:
number
;
};
export
const
Dashboard
:
React
.
FC
=
React
.
memo
(()
=>
{
export
const
Dashboard
:
React
.
FC
=
React
.
memo
(()
=>
{
const
[
userCount
,
setUserCount
]
=
useState
(
0
);
//用户数量
const
[
userCount
,
setUserCount
]
=
useState
(
0
);
//用户数量
const
[
kbCount
,
setkbCount
]
=
useState
(
0
);
const
[
kbCount
,
setkbCount
]
=
useState
(
0
);
const
[
modelCount
,
setmodelCount
]
=
useState
(
0
);
const
[
modelCount
,
setmodelCount
]
=
useState
(
0
);
const
[
usersData
,
setUsersData
]
=
useState
<
UsersChartDataType
[]
>
([]);
const
[
chatData
,
setChatData
]
=
useState
<
chatDataType
[]
>
([]);
useEffect
(()
=>
{
useEffect
(()
=>
{
const
baseUrl
=
import
.
meta
.
env
.
VITE_PUBLIC_SERVER_URL
;
const
baseUrl
=
import
.
meta
.
env
.
VITE_PUBLIC_SERVER_URL
;
...
@@ -56,20 +66,29 @@ export const Dashboard: React.FC = React.memo(() => {
...
@@ -56,20 +66,29 @@ export const Dashboard: React.FC = React.memo(() => {
setmodelCount
(
Number
(
modelTotalCount
));
setmodelCount
(
Number
(
modelTotalCount
));
}
}
};
};
const
fetchUserData
=
async
()
=>
{
const
userResponse
:
UsersChartDataType
[]
=
await
fetch
(
`
${
baseUrl
}
/users/data`
,
{
const
fetchChatData
=
async
()
=>
{
const
[
userResponse
,
payResponse
]:
fetchChatData
[][]
=
await
Promise
.
all
([
fetch
(
`
${
baseUrl
}
/users/data`
,
{
headers
headers
}).
then
((
res
)
=>
res
.
json
());
}).
then
((
res
)
=>
res
.
json
()),
setUsersData
(
fetch
(
`
${
baseUrl
}
/pays/data`
,
{
userResponse
.
map
((
item
)
=>
({
headers
...
item
,
}).
then
((
res
)
=>
res
.
json
())
date
:
dayjs
(
item
.
date
).
format
(
'MM/DD'
)
]);
}))
);
const
data
=
userResponse
.
map
((
item
,
i
)
=>
({
date
:
dayjs
(
item
.
date
).
format
(
'MM/DD'
),
userCount
:
item
.
count
,
userIncrease
:
item
.
increase
,
userIncreaseRate
:
item
.
increaseRate
,
payCount
:
payResponse
[
i
].
count
/
PRICE_SCALE
}));
setChatData
(
data
);
};
};
fetchCounts
();
fetchCounts
();
fetch
User
Data
();
fetch
Chat
Data
();
},
[]);
},
[]);
return
(
return
(
...
@@ -101,7 +120,13 @@ export const Dashboard: React.FC = React.memo(() => {
...
@@ -101,7 +120,13 @@ export const Dashboard: React.FC = React.memo(() => {
</
Grid
.
Row
>
</
Grid
.
Row
>
<
Divider
/>
<
Divider
/>
<
UserChart
data=
{
usersData
}
/>
<
div
>
<
strong
>
用户数量
&
支付情况
</
strong
>
<
UserChart
data=
{
chatData
}
/>
</
div
>
<
Divider
/>
</
Card
>
</
Card
>
</
Space
>
</
Space
>
</
div
>
</
div
>
...
@@ -162,7 +187,7 @@ const DataItem = React.memo((props: { icon: React.ReactElement; title: string; c
...
@@ -162,7 +187,7 @@ const DataItem = React.memo((props: { icon: React.ReactElement; title: string; c
DataItem
.
displayName
=
'DataItem'
;
DataItem
.
displayName
=
'DataItem'
;
const
CustomTooltip
=
({
active
,
payload
}:
any
)
=>
{
const
CustomTooltip
=
({
active
,
payload
}:
any
)
=>
{
const
data
=
payload
?.[
0
]?.
payload
as
UsersChar
tDataType
;
const
data
=
payload
?.[
0
]?.
payload
as
cha
tDataType
;
if
(
active
&&
data
)
{
if
(
active
&&
data
)
{
return
(
return
(
<
div
<
div
...
@@ -174,13 +199,16 @@ const CustomTooltip = ({ active, payload }: any) => {
...
@@ -174,13 +199,16 @@ const CustomTooltip = ({ active, payload }: any) => {
}
}
}
}
>
>
<
p
className=
"label"
>
<
p
className=
"label"
>
count:
<
strong
>
{
data
.
c
ount
}
</
strong
>
用户总数:
<
strong
>
{
data
.
userC
ount
}
</
strong
>
</
p
>
</
p
>
<
p
className=
"label"
>
<
p
className=
"label"
>
increase:
<
strong
>
{
data
.
increase
}
</
strong
>
60天累计支付:
<
strong
>
{
data
.
payCount
}
</
strong
>
元
</
p
>
</
p
>
<
p
className=
"label"
>
<
p
className=
"label"
>
increaseRate:
<
strong
>
{
data
.
increaseRate
}
</
strong
>
用户昨日增长数量:
<
strong
>
{
data
.
userIncrease
}
</
strong
>
</
p
>
<
p
className=
"label"
>
用户昨日增长比例:
<
strong
>
{
data
.
userIncreaseRate
}
</
strong
>
</
p
>
</
p
>
</
div
>
</
div
>
);
);
...
@@ -188,7 +216,7 @@ const CustomTooltip = ({ active, payload }: any) => {
...
@@ -188,7 +216,7 @@ const CustomTooltip = ({ active, payload }: any) => {
return
null
;
return
null
;
};
};
const
UserChart
=
({
data
}:
{
data
:
UsersChar
tDataType
[]
})
=>
{
const
UserChart
=
({
data
}:
{
data
:
cha
tDataType
[]
})
=>
{
return
(
return
(
<
ResponsiveContainer
width=
"100%"
height=
{
320
}
>
<
ResponsiveContainer
width=
"100%"
height=
{
320
}
>
<
AreaChart
<
AreaChart
...
@@ -198,14 +226,14 @@ const UserChart = ({ data }: { data: UsersChartDataType[] }) => {
...
@@ -198,14 +226,14 @@ const UserChart = ({ data }: { data: UsersChartDataType[] }) => {
margin=
{
{
top
:
10
,
right
:
30
,
left
:
0
,
bottom
:
0
}
}
margin=
{
{
top
:
10
,
right
:
30
,
left
:
0
,
bottom
:
0
}
}
>
>
<
defs
>
<
defs
>
<
linearGradient
id=
"colorUv"
x1=
"0"
y1=
"0"
x2=
"0"
y2=
"1"
>
<
linearGradient
id=
"userCount"
x1=
"0"
y1=
"0"
x2=
"0"
y2=
"1"
>
<
stop
offset=
"5%"
stopColor=
"#8884d8"
stopOpacity=
{
0.8
}
/>
<
stop
offset=
"95%"
stopColor=
"#8884d8"
stopOpacity=
{
0
}
/>
</
linearGradient
>
<
linearGradient
id=
"colorPv"
x1=
"0"
y1=
"0"
x2=
"0"
y2=
"1"
>
<
stop
offset=
"5%"
stopColor=
"#82ca9d"
stopOpacity=
{
0.8
}
/>
<
stop
offset=
"5%"
stopColor=
"#82ca9d"
stopOpacity=
{
0.8
}
/>
<
stop
offset=
"95%"
stopColor=
"#82ca9d"
stopOpacity=
{
0
}
/>
<
stop
offset=
"95%"
stopColor=
"#82ca9d"
stopOpacity=
{
0
}
/>
</
linearGradient
>
</
linearGradient
>
<
linearGradient
id=
"payCount"
x1=
"0"
y1=
"0"
x2=
"0"
y2=
"1"
>
<
stop
offset=
"5%"
stopColor=
"#8884d8"
stopOpacity=
{
0.8
}
/>
<
stop
offset=
"95%"
stopColor=
"#8884d8"
stopOpacity=
{
0
}
/>
</
linearGradient
>
</
defs
>
</
defs
>
<
XAxis
dataKey=
"date"
/>
<
XAxis
dataKey=
"date"
/>
<
YAxis
/>
<
YAxis
/>
...
@@ -213,10 +241,17 @@ const UserChart = ({ data }: { data: UsersChartDataType[] }) => {
...
@@ -213,10 +241,17 @@ const UserChart = ({ data }: { data: UsersChartDataType[] }) => {
<
Tooltip
content=
{
<
CustomTooltip
/>
}
/>
<
Tooltip
content=
{
<
CustomTooltip
/>
}
/>
<
Area
<
Area
type=
"monotone"
type=
"monotone"
dataKey=
"
c
ount"
dataKey=
"
userC
ount"
stroke=
"#82ca9d"
stroke=
"#82ca9d"
fillOpacity=
{
1
}
fillOpacity=
{
1
}
fill=
"url(#colorPv)"
fill=
"url(#userCount)"
/>
<
Area
type=
"monotone"
dataKey=
"payCount"
stroke=
"#8884d8"
fillOpacity=
{
1
}
fill=
"url(#payCount)"
/>
/>
</
AreaChart
>
</
AreaChart
>
</
ResponsiveContainer
>
</
ResponsiveContainer
>
...
...
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