Yansen 2 년 전
부모
커밋
e629563b64

+ 1
- 0
package.json 파일 보기

@@ -14,6 +14,7 @@
14 14
     "antd": "^4.22.3",
15 15
     "react": "18.1.0",
16 16
     "react-dom": "18.1.0",
17
+    "react-helmet": "^6.1.0",
17 18
     "react-router-dom": "6",
18 19
     "react-transition-group": "^4.4.5"
19 20
   },

+ 34
- 0
pnpm-lock.yaml 파일 보기

@@ -10,6 +10,7 @@ specifiers:
10 10
   less: ^4.1.3
11 11
   react: 18.1.0
12 12
   react-dom: 18.1.0
13
+  react-helmet: ^6.1.0
13 14
   react-router-dom: '6'
14 15
   react-transition-group: ^4.4.5
15 16
   vite: ^3.0.0
@@ -21,6 +22,7 @@ dependencies:
21 22
   antd: registry.npmmirror.com/antd/4.22.3_ef5jwxihqo6n7gxfmzogljlgcm
22 23
   react: registry.npmmirror.com/react/18.1.0
23 24
   react-dom: registry.npmmirror.com/react-dom/18.1.0_react@18.1.0
25
+  react-helmet: registry.npmmirror.com/react-helmet/6.1.0_react@18.1.0
24 26
   react-router-dom: registry.npmmirror.com/react-router-dom/6.3.0_ef5jwxihqo6n7gxfmzogljlgcm
25 27
   react-transition-group: registry.npmmirror.com/react-transition-group/4.4.5_ef5jwxihqo6n7gxfmzogljlgcm
26 28
 
@@ -2089,6 +2091,27 @@ packages:
2089 2091
       scheduler: registry.npmmirror.com/scheduler/0.22.0
2090 2092
     dev: false
2091 2093
 
2094
+  registry.npmmirror.com/react-fast-compare/3.2.0:
2095
+    resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz}
2096
+    name: react-fast-compare
2097
+    version: 3.2.0
2098
+    dev: false
2099
+
2100
+  registry.npmmirror.com/react-helmet/6.1.0_react@18.1.0:
2101
+    resolution: {integrity: sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-helmet/-/react-helmet-6.1.0.tgz}
2102
+    id: registry.npmmirror.com/react-helmet/6.1.0
2103
+    name: react-helmet
2104
+    version: 6.1.0
2105
+    peerDependencies:
2106
+      react: '>=16.3.0'
2107
+    dependencies:
2108
+      object-assign: registry.npmmirror.com/object-assign/4.1.1
2109
+      prop-types: registry.npmmirror.com/prop-types/15.8.1
2110
+      react: registry.npmmirror.com/react/18.1.0
2111
+      react-fast-compare: registry.npmmirror.com/react-fast-compare/3.2.0
2112
+      react-side-effect: registry.npmmirror.com/react-side-effect/2.1.2_react@18.1.0
2113
+    dev: false
2114
+
2092 2115
   registry.npmmirror.com/react-is/16.13.1:
2093 2116
     resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz}
2094 2117
     name: react-is
@@ -2129,6 +2152,17 @@ packages:
2129 2152
       react: registry.npmmirror.com/react/18.1.0
2130 2153
     dev: false
2131 2154
 
2155
+  registry.npmmirror.com/react-side-effect/2.1.2_react@18.1.0:
2156
+    resolution: {integrity: sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-side-effect/-/react-side-effect-2.1.2.tgz}
2157
+    id: registry.npmmirror.com/react-side-effect/2.1.2
2158
+    name: react-side-effect
2159
+    version: 2.1.2
2160
+    peerDependencies:
2161
+      react: ^16.3.0 || ^17.0.0 || ^18.0.0
2162
+    dependencies:
2163
+      react: registry.npmmirror.com/react/18.1.0
2164
+    dev: false
2165
+
2132 2166
   registry.npmmirror.com/react-transition-group/4.4.5_ef5jwxihqo6n7gxfmzogljlgcm:
2133 2167
     resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/react-transition-group/-/react-transition-group-4.4.5.tgz}
2134 2168
     id: registry.npmmirror.com/react-transition-group/4.4.5

+ 110
- 0
public/particles/particles.json 파일 보기

@@ -0,0 +1,110 @@
1
+{
2
+  "particles": {
3
+    "number": {
4
+      "value": 80,
5
+      "density": {
6
+        "enable": true,
7
+        "value_area": 800
8
+      }
9
+    },
10
+    "color": {
11
+      "value": "#1890ff"
12
+    },
13
+    "shape": {
14
+      "type": "circle",
15
+      "stroke": {
16
+        "width": 0,
17
+        "color": "#000000"
18
+      },
19
+      "polygon": {
20
+        "nb_sides": 5
21
+      },
22
+      "image": {
23
+        "src": "img/github.svg",
24
+        "width": 100,
25
+        "height": 100
26
+      }
27
+    },
28
+    "opacity": {
29
+      "value": 0.5,
30
+      "random": false,
31
+      "anim": {
32
+        "enable": false,
33
+        "speed": 1,
34
+        "opacity_min": 0.1,
35
+        "sync": false
36
+      }
37
+    },
38
+    "size": {
39
+      "value": 3,
40
+      "random": true,
41
+      "anim": {
42
+        "enable": false,
43
+        "speed": 40,
44
+        "size_min": 0.1,
45
+        "sync": false
46
+      }
47
+    },
48
+    "line_linked": {
49
+      "enable": true,
50
+      "distance": 150,
51
+      "color": "#1890ff",
52
+      "opacity": 0.4,
53
+      "width": 1
54
+    },
55
+    "move": {
56
+      "enable": true,
57
+      "speed": 6,
58
+      "direction": "none",
59
+      "random": false,
60
+      "straight": false,
61
+      "out_mode": "out",
62
+      "bounce": false,
63
+      "attract": {
64
+        "enable": false,
65
+        "rotateX": 600,
66
+        "rotateY": 1200
67
+      }
68
+    }
69
+  },
70
+  "interactivity": {
71
+    "detect_on": "canvas",
72
+    "events": {
73
+      "onhover": {
74
+        "enable": false,
75
+        "mode": "repulse"
76
+      },
77
+      "onclick": {
78
+        "enable": false,
79
+        "mode": "push"
80
+      },
81
+      "resize": true
82
+    },
83
+    "modes": {
84
+      "grab": {
85
+        "distance": 400,
86
+        "line_linked": {
87
+          "opacity": 1
88
+        }
89
+      },
90
+      "bubble": {
91
+        "distance": 400,
92
+        "size": 40,
93
+        "duration": 2,
94
+        "opacity": 8,
95
+        "speed": 3
96
+      },
97
+      "repulse": {
98
+        "distance": 200,
99
+        "duration": 0.4
100
+      },
101
+      "push": {
102
+        "particles_nb": 4
103
+      },
104
+      "remove": {
105
+        "particles_nb": 2
106
+      }
107
+    }
108
+  },
109
+  "retina_detect": true
110
+}

+ 9
- 0
public/particles/particles.min.js
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 2
- 6
src/components/page/index.jsx 파일 보기

@@ -1,16 +1,12 @@
1 1
 import React from 'react';
2 2
 import { PageHeader } from 'antd';
3
-import { useLocation } from "react-router-dom";
4
-import { getRouteArr } from '@/routes/menus';
3
+import useRoute from '@/routes/useRoute';
5 4
 import './style.less'
6 5
 
7 6
 export default (props) => {
8 7
   const { children, ...headerProps } = props;
9 8
 
10
-  const location = useLocation();
11
-  const routeArr = getRouteArr();
12
-
13
-  const currentRoute = routeArr.filter(x => x.path === location.pathname)[0] || {};
9
+  const currentRoute = useRoute() || {};
14 10
   const { title } = currentRoute.meta || {};
15 11
 
16 12
   return (

+ 1
- 1
src/layouts/AuthLayout/components/Header/Logo.jsx 파일 보기

@@ -8,7 +8,7 @@ export default (props) => {
8 8
   return (
9 9
     <div className='logo'>
10 10
       <img src="./logo.png" alt="" />
11
-      <h3>{config.appName}</h3>
11
+      <h3>{config.shorName}</h3>
12 12
     </div>
13 13
   )
14 14
 }

+ 10
- 1
src/layouts/AuthLayout/index.jsx 파일 보기

@@ -1,6 +1,8 @@
1 1
 import React, { useEffect, useRef, useMemo, useState } from 'react';
2 2
 import { Layout, Spin } from 'antd';
3
-import { useModel } from '@/store'
3
+import { Helmet } from "react-helmet";
4
+import { useModel } from '@/store';
5
+import useRoute from '@/routes/useRoute';
4 6
 import RequireLogin from './components/RequireLogin';
5 7
 import SiderBar from './components/SiderBar';
6 8
 import Header from './components/Header';
@@ -10,10 +12,14 @@ import useReady from './useReady';
10 12
 import './style.less';
11 13
 
12 14
 export default (props) => {
15
+  const { config } = useModel('system');
13 16
   const { user, getCurrent } = useModel('user');
14 17
   // const isReady = useReady(user)
15 18
   // const isReady = true
16 19
 
20
+  const currentRoute = useRoute();
21
+  const pageTitle = currentRoute && currentRoute.meta ? currentRoute.meta.title : undefined;
22
+  const fullTitle = pageTitle ? `${pageTitle} | ${config.appName}` : config.appName;
17 23
 
18 24
   useEffect(() => {
19 25
     if (!user) {
@@ -23,6 +29,9 @@ export default (props) => {
23 29
 
24 30
   return (
25 31
     <Spin spinning={!user} size="large">
32
+      <Helmet>
33
+        <title>{fullTitle}</title>
34
+      </Helmet>
26 35
       <RequireLogin>
27 36
         <div className='main-layout'>
28 37
           <Header />

+ 7
- 0
src/pages/404/index.jsx 파일 보기

@@ -1,6 +1,8 @@
1 1
 import React from 'react';
2 2
 import { Button, Result } from 'antd';
3
+import { Helmet } from "react-helmet";
3 4
 import { NavLink } from "react-router-dom";
5
+import { useModel } from '@/store';
4 6
 
5 7
 const style = {
6 8
   display: 'grid',
@@ -9,8 +11,13 @@ const style = {
9 11
 }
10 12
 
11 13
 export default (props) => {
14
+  const { config } = useModel('system');
15
+
12 16
   return (
13 17
     <div style={style}>
18
+      <Helmet>
19
+        <title>{config.appName}</title>
20
+      </Helmet>
14 21
       <Result
15 22
         status="404"
16 23
         title="404"

+ 12
- 2
src/pages/login/index.jsx 파일 보기

@@ -1,4 +1,6 @@
1 1
 import React from 'react';
2
+import { Helmet } from "react-helmet";
3
+import { useModel } from '@/store';
2 4
 import LoginForm from './LoginForm';
3 5
 import LoginEffect from './Effect';
4 6
 import './style.less'
@@ -6,19 +8,27 @@ import './style.less'
6 8
 const year = new Date().getFullYear();
7 9
 
8 10
 export default (props) => {
11
+  const { config } = useModel('system');
12
+
13
+  const title = `欢迎使用${config.appName}`
14
+  const copyright = `${config.company} @ ${year}`
15
+
9 16
   return (
10 17
     <div className='login-page'>
18
+      <Helmet>
19
+        <title>{config.appName}</title>
20
+      </Helmet>
11 21
       <div className="login-card">
12 22
         <div className="login-card-left">
13 23
           <div className="login-form-box">
14 24
             <div className="login-form">
15 25
               <h2>登录系统</h2>
16
-              <div className="login-subtitle">欢迎使用云致管理系统</div>
26
+              <div className="login-subtitle">{title}</div>
17 27
               <LoginForm />
18 28
             </div>
19 29
           </div>
20 30
           <div className="login-copyright">
21
-          南京云致 @ {year}
31
+            {copyright}
22 32
           </div>
23 33
         </div>
24 34
         <div className="login-card-right">

+ 7
- 2
src/pages/login/style.less 파일 보기

@@ -28,10 +28,15 @@
28 28
     display: grid;
29 29
     place-items: center;
30 30
 
31
+    .login-form {
32
+      min-width: 280px;
33
+    }
34
+
31 35
     .login-subtitle {
32 36
       font-size: .9em;
33 37
       color: #666;
34 38
       margin-bottom: 24px;
39
+      letter-spacing: 2px;
35 40
     }
36 41
   }
37 42
 
@@ -41,8 +46,8 @@
41 46
     place-items: center;
42 47
 
43 48
     .login-effect {
44
-      width: 120px;
45
-      height: 120px;
49
+      width: 180px;
50
+      height: 180px;
46 51
       position: relative;
47 52
     }
48 53
 

+ 11
- 0
src/routes/useRoute.jsx 파일 보기

@@ -0,0 +1,11 @@
1
+import { useLocation } from "react-router-dom";
2
+import { getRouteArr } from './menus';
3
+
4
+export default function useRoute() {
5
+  const location = useLocation();
6
+  const routeArr = getRouteArr();
7
+
8
+  const currentRoute = routeArr.filter(x => x.path === location.pathname)[0];
9
+
10
+  return currentRoute;
11
+}

+ 3
- 1
src/store/models/system.js 파일 보기

@@ -8,7 +8,9 @@ const setRootCssVar = (key, val) => {
8 8
 export default function useSystem() {
9 9
   const [theme, setTheme] = useState('light');
10 10
   const [config, setConfig] = useState({
11
-    appName: '云致科技',
11
+    appName: '云致科技信息管理系统',
12
+    shorName: '云致科技',
13
+    company: '云致科技'
12 14
   });
13 15
 
14 16
   const updateTheme = useCallback((t) => {