diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7e2d3c44..9a7c17e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -921,6 +921,7 @@ importers: react: ^18.2.0 react-admin: ^4.6.3 react-dom: ^18.2.0 + react-router-dom: ^6.5.0 ts-node: ^10.9.1 typescript: ^4.8.4 dependencies: @@ -937,10 +938,11 @@ importers: isbot: 3.6.5 lodash: 4.17.21 morgan: 1.10.0 - ra-data-json-server: 4.6.3_biqbaboplfbrettd7655fr4n2y + ra-data-json-server: 4.6.3_7gebip3sgfc5uoqbhvi5xascza react: 18.2.0 react-admin: 4.6.3_ib3m5ricvtkl2cll7qpr2f6lvq react-dom: 18.2.0_react@18.2.0 + react-router-dom: 6.5.0_biqbaboplfbrettd7655fr4n2y ts-node: 10.9.1_typescript@4.9.4 devDependencies: '@remix-run/dev': 1.9.0_biqbaboplfbrettd7655fr4n2y @@ -31066,7 +31068,7 @@ packages: quill-delta: 3.6.3 dev: false - /ra-core/4.6.3_biqbaboplfbrettd7655fr4n2y: + /ra-core/4.6.3_7gebip3sgfc5uoqbhvi5xascza: resolution: {integrity: sha512-++UW1HJDy1m5EG8/6nRNr8btHxb7I5e5dMJXo83h0E7g5st2U6bIR0XLzIdcirOy5k3h3rM0lZP+tEA9M/Oxyw==} peerDependencies: history: ^5.1.0 @@ -31088,6 +31090,7 @@ packages: react-dom: 18.2.0_react@18.2.0 react-is: 17.0.2 react-query: 3.39.2_biqbaboplfbrettd7655fr4n2y + react-router-dom: 6.5.0_biqbaboplfbrettd7655fr4n2y transitivePeerDependencies: - react-native dev: false @@ -31122,11 +31125,11 @@ packages: - react-native dev: false - /ra-data-json-server/4.6.3_biqbaboplfbrettd7655fr4n2y: + /ra-data-json-server/4.6.3_7gebip3sgfc5uoqbhvi5xascza: resolution: {integrity: sha512-KChdLr/quUimzzsl5XTBc6jGg7EvQgjlRFi4Ymk8ovD/I11m2Vz8iXwgAV2kWDMKPqFuaRC9/xd6XZwjD/5zQQ==} dependencies: query-string: 7.1.3 - ra-core: 4.6.3_biqbaboplfbrettd7655fr4n2y + ra-core: 4.6.3_7gebip3sgfc5uoqbhvi5xascza transitivePeerDependencies: - history - react diff --git a/server/admin/app/ra/App.tsx b/server/admin/app/ra/App.tsx index 78aa81db..8b84c958 100644 --- a/server/admin/app/ra/App.tsx +++ b/server/admin/app/ra/App.tsx @@ -18,6 +18,7 @@ import MessageIcon from '@mui/icons-material/Message'; import GroupIcon from '@mui/icons-material/Group'; import AttachFileIcon from '@mui/icons-material/AttachFile'; import { theme } from './theme'; +import { Dashboard } from './dashboard'; const httpClient: typeof fetchUtils.fetchJson = (url, options = {}) => { try { @@ -43,6 +44,8 @@ export const App = () => ( diff --git a/server/admin/app/ra/dashboard/CardWithIcon.tsx b/server/admin/app/ra/dashboard/CardWithIcon.tsx new file mode 100644 index 00000000..752f1e07 --- /dev/null +++ b/server/admin/app/ra/dashboard/CardWithIcon.tsx @@ -0,0 +1,70 @@ +import * as React from 'react'; +import { FC, createElement } from 'react'; +import { Card, Box, Typography, Divider } from '@mui/material'; +import { Link, To } from 'react-router-dom'; +import { ReactNode } from 'react'; +import { LoadingIndicator } from 'react-admin'; + +import cartouche from './cartouche.png'; +import cartoucheDark from './cartoucheDark.png'; + +interface Props { + icon: FC; + to: To; + title?: string; + subtitle?: string | number; + children?: ReactNode; +} + +const CardWithIcon = (props: Props) => { + const { icon, title, subtitle, to, children } = props; + + return ( + + + + `url(${ + theme.palette.mode === 'dark' ? cartoucheDark : cartouche + }) no-repeat`, + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + '& .icon': { + color: (theme) => + theme.palette.mode === 'dark' ? 'inherit' : '#dc2440', + }, + }} + > + + {createElement(icon, { fontSize: 'large' })} + + + {title} + + {subtitle || } + + + + + {children && } + {children} + + ); +}; + +export default CardWithIcon; diff --git a/server/admin/app/ra/dashboard/Welcome.tsx b/server/admin/app/ra/dashboard/Welcome.tsx new file mode 100644 index 00000000..8376ca84 --- /dev/null +++ b/server/admin/app/ra/dashboard/Welcome.tsx @@ -0,0 +1,77 @@ +import React from 'react'; +import { Card, Box, Typography, CardActions, Button } from '@mui/material'; +import HomeIcon from '@mui/icons-material/Home'; +import CodeIcon from '@mui/icons-material/Code'; +import logoSvg from './logo.svg'; + +export const Welcome: React.FC = React.memo(() => { + return ( + + theme.palette.mode === 'dark' + ? '#535353' + : `linear-gradient(to right, #1a1d26 0%, #232c50 35%)`, + + color: '#fff', + padding: '20px', + marginTop: 2, + marginBottom: '1em', + }} + > + + + + 欢迎使用 Tailchat 后台管理程序 + + + + Tailchat 是一个完全开源的即时通讯应用 + + + + + + + + + + + ); +}); +Welcome.displayName = 'Welcome'; diff --git a/server/admin/app/ra/dashboard/cartouche.png b/server/admin/app/ra/dashboard/cartouche.png new file mode 100644 index 00000000..06de31c0 Binary files /dev/null and b/server/admin/app/ra/dashboard/cartouche.png differ diff --git a/server/admin/app/ra/dashboard/cartoucheDark.png b/server/admin/app/ra/dashboard/cartoucheDark.png new file mode 100644 index 00000000..98d1f76e Binary files /dev/null and b/server/admin/app/ra/dashboard/cartoucheDark.png differ diff --git a/server/admin/app/ra/dashboard/index.tsx b/server/admin/app/ra/dashboard/index.tsx new file mode 100644 index 00000000..d1b4c470 --- /dev/null +++ b/server/admin/app/ra/dashboard/index.tsx @@ -0,0 +1,78 @@ +import React from 'react'; +import CardWithIcon from './CardWithIcon'; +import { Welcome } from './Welcome'; +import PersonIcon from '@mui/icons-material/Person'; +import MessageIcon from '@mui/icons-material/Message'; +import GroupIcon from '@mui/icons-material/Group'; +import AttachFileIcon from '@mui/icons-material/AttachFile'; +import { useGetList } from 'react-admin'; +import { Grid } from '@mui/material'; + +export const Dashboard: React.FC = React.memo(() => { + const { total: usersNum } = useGetList('users', { + pagination: { page: 1, perPage: 1 }, + }); + const { total: tempUsersNum } = useGetList('users', { + filter: { temporary: true }, + pagination: { page: 1, perPage: 1 }, + }); + const { total: messageNum } = useGetList('messages', { + pagination: { page: 1, perPage: 1 }, + }); + const { total: groupNum } = useGetList('groups', { + pagination: { page: 1, perPage: 1 }, + }); + const { total: fileNum } = useGetList('file', { + pagination: { page: 1, perPage: 1 }, + }); + + return ( +
+ + + + + + + + + + + + + + + + + + + +
+ ); +}); +Dashboard.displayName = 'Dashboard'; diff --git a/server/admin/app/ra/dashboard/logo.svg b/server/admin/app/ra/dashboard/logo.svg new file mode 100644 index 00000000..b2c7ed9f --- /dev/null +++ b/server/admin/app/ra/dashboard/logo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/server/admin/app/ra/resources/group.tsx b/server/admin/app/ra/resources/group.tsx index 973e68f4..82a8732a 100644 --- a/server/admin/app/ra/resources/group.tsx +++ b/server/admin/app/ra/resources/group.tsx @@ -29,11 +29,7 @@ export const GroupList: React.FC = () => ( - - - - - + diff --git a/server/admin/package.json b/server/admin/package.json index 1795efed..613e0e8f 100644 --- a/server/admin/package.json +++ b/server/admin/package.json @@ -28,6 +28,7 @@ "react": "^18.2.0", "react-admin": "^4.6.3", "react-dom": "^18.2.0", + "react-router-dom": "^6.5.0", "ts-node": "^10.9.1" }, "devDependencies": {