Yansen před 2 roky
rodič
revize
331678c0bc
100 změnil soubory, kde provedl 6411 přidání a 3798 odebrání
  1. 0
    16
      .editorconfig
  2. 1
    0
      .env
  3. 1
    0
      .env.production
  4. 0
    8
      .eslintignore
  5. 0
    8
      .eslintrc.js
  6. 22
    38
      .gitignore
  7. 0
    23
      .prettierignore
  8. 0
    5
      .prettierrc.js
  9. 0
    57
      README.md
  10. 0
    58
      config/config.js
  11. 0
    20
      config/defaultSettings.js
  12. 0
    593
      config/oneapi.json
  13. 0
    35
      config/proxy.js
  14. 0
    148
      config/routes.js
  15. 13
    0
      index.html
  16. 0
    9
      jest.config.js
  17. 0
    3
      jsconfig.json
  18. 0
    174
      mock/listTableList.ts
  19. 0
    107
      mock/notices.ts
  20. 0
    5
      mock/route.ts
  21. 0
    203
      mock/user.ts
  22. 2310
    0
      package-lock.json
  23. 24
    111
      package.json
  24. 0
    22
      playwright.config.ts
  25. 3109
    0
      pnpm-lock.yaml
  26. 0
    1
      public/CNAME
  27. binární
      public/favicon.ico
  28. binární
      public/logo.png
  29. 1
    0
      public/vite.svg
  30. 42
    0
      src/App.css
  31. 0
    9
      src/access.ts
  32. 5
    113
      src/app.jsx
  33. 1
    0
      src/assets/react.svg
  34. 0
    18
      src/components/Footer/index.jsx
  35. 0
    16
      src/components/HeaderDropdown/index.jsx
  36. 0
    16
      src/components/HeaderDropdown/index.less
  37. 0
    105
      src/components/HeaderSearch/index.jsx
  38. 0
    25
      src/components/HeaderSearch/index.less
  39. 0
    126
      src/components/NoticeIcon/NoticeIcon.tsx
  40. 0
    103
      src/components/NoticeIcon/NoticeList.less
  41. 0
    112
      src/components/NoticeIcon/NoticeList.tsx
  42. 0
    152
      src/components/NoticeIcon/index.jsx
  43. 0
    35
      src/components/NoticeIcon/index.less
  44. 0
    112
      src/components/RightContent/AvatarDropdown.jsx
  45. 0
    27
      src/components/RightContent/index.jsx
  46. 0
    75
      src/components/RightContent/index.less
  47. 1
    1
      src/components/UploadFile/index.jsx
  48. 1
    1
      src/components/UploadVideo/index.jsx
  49. 81
    0
      src/components/chart/index.jsx
  50. 0
    267
      src/components/index.md
  51. 10
    0
      src/components/page/Container.jsx
  52. 14
    0
      src/components/page/index.jsx
  53. 5
    0
      src/components/page/style.less
  54. 0
    45
      src/e2e/baseLayout.e2e.spec.ts
  55. 0
    91
      src/global.jsx
  56. 0
    102
      src/global.less
  57. 77
    0
      src/index.less
  58. 30
    0
      src/layouts/AuthLayout/components/Container.jsx
  59. 14
    0
      src/layouts/AuthLayout/components/Footer.jsx
  60. 28
    0
      src/layouts/AuthLayout/components/Header/Exit.jsx
  61. 28
    0
      src/layouts/AuthLayout/components/Header/SplitMenu.jsx
  62. 26
    0
      src/layouts/AuthLayout/components/Header/Title.jsx
  63. 88
    0
      src/layouts/AuthLayout/components/Header/User.jsx
  64. 30
    0
      src/layouts/AuthLayout/components/Header/index.jsx
  65. 19
    0
      src/layouts/AuthLayout/components/HtmlTitle.jsx
  66. 17
    0
      src/layouts/AuthLayout/components/Logo.jsx
  67. 41
    0
      src/layouts/AuthLayout/components/Menus.jsx
  68. 21
    0
      src/layouts/AuthLayout/components/PageTransition/index.jsx
  69. 21
    0
      src/layouts/AuthLayout/components/PageTransition/style.less
  70. 13
    0
      src/layouts/AuthLayout/components/RequireLogin.jsx
  71. 20
    0
      src/layouts/AuthLayout/components/SiderBar.jsx
  72. 48
    0
      src/layouts/AuthLayout/index.jsx
  73. 105
    0
      src/layouts/AuthLayout/style.less
  74. 21
    0
      src/layouts/AuthLayout/useReady.jsx
  75. 15
    0
      src/layouts/Container.jsx
  76. 11
    0
      src/main.jsx
  77. 0
    22
      src/manifest.json
  78. 0
    18
      src/pages/404.jsx
  79. 29
    0
      src/pages/404/index.jsx
  80. 0
    45
      src/pages/Admin.jsx
  81. 0
    17
      src/pages/Welcome.jsx
  82. 0
    8
      src/pages/Welcome.less
  83. 6
    5
      src/pages/dish/edit/index.jsx
  84. 6
    5
      src/pages/dish/list/index.jsx
  85. 0
    236
      src/pages/document.ejs
  86. 5
    5
      src/pages/guaranteeTask/Edit/BasicForm.jsx
  87. 3
    3
      src/pages/guaranteeTask/Edit/DishList.jsx
  88. 2
    2
      src/pages/guaranteeTask/Edit/index.jsx
  89. 6
    5
      src/pages/guaranteeTask/index.jsx
  90. 3
    3
      src/pages/guaranteeTask/print/index.jsx
  91. 18
    19
      src/pages/login/index.jsx
  92. 3
    3
      src/pages/login/index.less
  93. 0
    43
      src/pages/monitor/edit.jsx
  94. 0
    151
      src/pages/monitor/index.jsx
  95. 1
    1
      src/pages/package/BasicForm.jsx
  96. 2
    2
      src/pages/package/DishList.jsx
  97. 1
    1
      src/pages/package/List.jsx
  98. 7
    5
      src/pages/rotationChart/edit/index.jsx
  99. 5
    4
      src/pages/rotationChart/list/index.jsx
  100. 0
    0
      src/pages/sample/form/index.jsx

+ 0
- 16
.editorconfig Zobrazit soubor

@@ -1,16 +0,0 @@
1
-# http://editorconfig.org
2
-root = true
3
-
4
-[*]
5
-indent_style = space
6
-indent_size = 2
7
-end_of_line = lf
8
-charset = utf-8
9
-trim_trailing_whitespace = true
10
-insert_final_newline = true
11
-
12
-[*.md]
13
-trim_trailing_whitespace = false
14
-
15
-[Makefile]
16
-indent_style = tab

+ 1
- 0
.env Zobrazit soubor

@@ -0,0 +1 @@
1
+VITE_SERVER_BASE=/api

+ 1
- 0
.env.production Zobrazit soubor

@@ -0,0 +1 @@
1
+VITE_SERVER_BASE=/api

+ 0
- 8
.eslintignore Zobrazit soubor

@@ -1,8 +0,0 @@
1
-/lambda/
2
-/scripts
3
-/config
4
-.history
5
-public
6
-dist
7
-.umi
8
-mock

+ 0
- 8
.eslintrc.js Zobrazit soubor

@@ -1,8 +0,0 @@
1
-module.exports = {
2
-  extends: [require.resolve('@umijs/fabric/dist/eslint')],
3
-  globals: {
4
-    ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
5
-    page: true,
6
-    REACT_APP_ENV: true,
7
-  },
8
-};

+ 22
- 38
.gitignore Zobrazit soubor

@@ -1,40 +1,24 @@
1
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
-
3
-# dependencies
4
-**/node_modules
5
-# roadhog-api-doc ignore
6
-/src/utils/request-temp.js
7
-_roadhog-api-doc
8
-
9
-# production
10
-/dist
11
-
12
-# misc
13
-.DS_Store
1
+# Logs
2
+logs
3
+*.log
14 4
 npm-debug.log*
15
-yarn-error.log
16
-
17
-/coverage
5
+yarn-debug.log*
6
+yarn-error.log*
7
+pnpm-debug.log*
8
+lerna-debug.log*
9
+
10
+node_modules
11
+dist
12
+dist-ssr
13
+*.local
14
+
15
+# Editor directories and files
16
+.vscode/*
17
+!.vscode/extensions.json
18 18
 .idea
19
-yarn.lock
20
-package-lock.json
21
-pnpm-lock.yaml
22
-*bak
23
-
24
-
25
-# visual studio code
26
-.history
27
-*.log
28
-functions/*
29
-.temp/**
30
-
31
-# umi
32
-.umi
33
-.umi-production
34
-
35
-# screenshot
36
-screenshot
37
-.firebase
38
-.eslintcache
39
-
40
-build
19
+.DS_Store
20
+*.suo
21
+*.ntvs*
22
+*.njsproj
23
+*.sln
24
+*.sw?

+ 0
- 23
.prettierignore Zobrazit soubor

@@ -1,23 +0,0 @@
1
-**/*.svg
2
-package.json
3
-.umi
4
-.umi-production
5
-/dist
6
-.dockerignore
7
-.DS_Store
8
-.eslintignore
9
-*.png
10
-*.toml
11
-docker
12
-.editorconfig
13
-Dockerfile*
14
-.gitignore
15
-.prettierignore
16
-LICENSE
17
-.eslintcache
18
-*.lock
19
-yarn-error.log
20
-.history
21
-CNAME
22
-/build
23
-/public

+ 0
- 5
.prettierrc.js Zobrazit soubor

@@ -1,5 +0,0 @@
1
-const fabric = require('@umijs/fabric');
2
-
3
-module.exports = {
4
-  ...fabric.prettier,
5
-};

+ 0
- 57
README.md Zobrazit soubor

@@ -1,57 +0,0 @@
1
-# Ant Design Pro
2
-
3
-This project is initialized with [Ant Design Pro](https://pro.ant.design). Follow is the quick guide for how to use.
4
-
5
-## Environment Prepare
6
-
7
-Install `node_modules`:
8
-
9
-```bash
10
-npm install
11
-```
12
-
13
-or
14
-
15
-```bash
16
-yarn
17
-```
18
-
19
-## Provided Scripts
20
-
21
-Ant Design Pro provides some useful script to help you quick start and build with web project, code style check and test.
22
-
23
-Scripts provided in `package.json`. It's safe to modify or add additional script:
24
-
25
-### Start project
26
-
27
-```bash
28
-npm start
29
-```
30
-
31
-### Build project
32
-
33
-```bash
34
-npm run build
35
-```
36
-
37
-### Check code style
38
-
39
-```bash
40
-npm run lint
41
-```
42
-
43
-You can also use script to auto fix some lint error:
44
-
45
-```bash
46
-npm run lint:fix
47
-```
48
-
49
-### Test code
50
-
51
-```bash
52
-npm test
53
-```
54
-
55
-## More
56
-
57
-You can view full document on our [official website](https://pro.ant.design). And welcome any feedback in our [github](https://github.com/ant-design/ant-design-pro).

+ 0
- 58
config/config.js Zobrazit soubor

@@ -1,58 +0,0 @@
1
-// https://umijs.org/config/
2
-import { defineConfig } from '@umijs/max';
3
-import { join } from 'path';
4
-import defaultSettings from './defaultSettings';
5
-import proxy from './proxy';
6
-import routes from './routes';
7
-
8
-const { REACT_APP_ENV } = process.env;
9
-
10
-export default defineConfig({
11
-  define: {
12
-    API_BASE: REACT_APP_ENV ? '' : ''
13
-  },
14
-  publicPath: '/w2/',
15
-  hash: true,
16
-  history: {
17
-    type: 'hash'
18
-  },
19
-  antd: {
20
-    dark: true,
21
-  },
22
-  request: {},
23
-  initialState: {},
24
-  model: {},
25
-  layout: {
26
-    // https://umijs.org/zh-CN/plugins/plugin-layout
27
-    locale: false,
28
-    siderWidth: 208,
29
-    ...defaultSettings,
30
-  },
31
-  // https://umijs.org/zh-CN/plugins/plugin-locale
32
-  locale: false,
33
-
34
-  jsMinifier: 'terser',
35
-  cssMinifier: 'cssnano',
36
-  targets: {
37
-    ie: 11,
38
-  },
39
-  // umi routes: https://umijs.org/docs/routing
40
-  routes,
41
-  access: {},
42
-  // Theme for antd: https://ant.design/docs/react/customize-theme-cn
43
-  theme: {
44
-    // 如果不想要 configProvide 动态设置主题需要把这个设置为 default
45
-    // 只有设置为 variable, 才能使用 configProvide 动态设置主色调
46
-    // https://ant.design/docs/react/customize-theme-variable-cn
47
-    'root-entry-name': 'variable',
48
-  },
49
-  ignoreMomentLocale: true,
50
-  proxy: proxy[REACT_APP_ENV || 'dev'],
51
-  manifest: {
52
-    basePath: '/',
53
-  },
54
-  // Fast Refresh 热更新
55
-  fastRefresh: true,
56
-  presets: ['umi-presets-pro'],
57
-  openAPI: false,
58
-});

+ 0
- 20
config/defaultSettings.js Zobrazit soubor

@@ -1,20 +0,0 @@
1
-
2
-const Settings = {
3
-  navTheme: 'dark',
4
-  // 拂晓蓝
5
-  primaryColor: '#1890ff',
6
-  contentWidth: 'Fluid',
7
-  colorWeak: false,
8
-  title: '', // 必须为空
9
-  pwa: false,
10
-  iconfontUrl: '',
11
-  footerRender: false,
12
-  menu: {
13
-    type: 'group'
14
-  },
15
-  fixSiderbar: true,
16
-  layout: 'mix',
17
-  splitMenus: true,
18
-};
19
-
20
-export default Settings;

+ 0
- 593
config/oneapi.json Zobrazit soubor

@@ -1,593 +0,0 @@
1
-{
2
-  "openapi": "3.0.1",
3
-  "info": {
4
-    "title": "Ant Design Pro",
5
-    "version": "1.0.0"
6
-  },
7
-  "servers": [
8
-    {
9
-      "url": "http://localhost:8000/"
10
-    },
11
-    {
12
-      "url": "https://localhost:8000/"
13
-    }
14
-  ],
15
-  "paths": {
16
-    "/api/currentUser": {
17
-      "get": {
18
-        "tags": ["api"],
19
-        "description": "获取当前的用户",
20
-        "operationId": "currentUser",
21
-        "responses": {
22
-          "200": {
23
-            "description": "Success",
24
-            "content": {
25
-              "application/json": {
26
-                "schema": {
27
-                  "$ref": "#/components/schemas/CurrentUser"
28
-                }
29
-              }
30
-            }
31
-          },
32
-          "401": {
33
-            "description": "Error",
34
-            "content": {
35
-              "application/json": {
36
-                "schema": {
37
-                  "$ref": "#/components/schemas/ErrorResponse"
38
-                }
39
-              }
40
-            }
41
-          }
42
-        }
43
-      },
44
-      "x-swagger-router-controller": "api"
45
-    },
46
-    "/api/login/captcha": {
47
-      "post": {
48
-        "description": "发送验证码",
49
-        "operationId": "getFakeCaptcha",
50
-        "tags": ["login"],
51
-        "parameters": [
52
-          {
53
-            "name": "phone",
54
-            "in": "query",
55
-            "description": "手机号",
56
-            "schema": {
57
-              "type": "string"
58
-            }
59
-          }
60
-        ],
61
-        "responses": {
62
-          "200": {
63
-            "description": "Success",
64
-            "content": {
65
-              "application/json": {
66
-                "schema": {
67
-                  "$ref": "#/components/schemas/FakeCaptcha"
68
-                }
69
-              }
70
-            }
71
-          }
72
-        }
73
-      }
74
-    },
75
-    "/api/login/outLogin": {
76
-      "post": {
77
-        "description": "登录接口",
78
-        "operationId": "outLogin",
79
-        "tags": ["login"],
80
-        "responses": {
81
-          "200": {
82
-            "description": "Success",
83
-            "content": {
84
-              "application/json": {
85
-                "schema": {
86
-                  "type": "object"
87
-                }
88
-              }
89
-            }
90
-          },
91
-          "401": {
92
-            "description": "Error",
93
-            "content": {
94
-              "application/json": {
95
-                "schema": {
96
-                  "$ref": "#/components/schemas/ErrorResponse"
97
-                }
98
-              }
99
-            }
100
-          }
101
-        }
102
-      },
103
-      "x-swagger-router-controller": "api"
104
-    },
105
-    "/api/login/account": {
106
-      "post": {
107
-        "tags": ["login"],
108
-        "description": "登录接口",
109
-        "operationId": "login",
110
-        "requestBody": {
111
-          "description": "登录系统",
112
-          "content": {
113
-            "application/json": {
114
-              "schema": {
115
-                "$ref": "#/components/schemas/LoginParams"
116
-              }
117
-            }
118
-          },
119
-          "required": true
120
-        },
121
-        "responses": {
122
-          "200": {
123
-            "description": "Success",
124
-            "content": {
125
-              "application/json": {
126
-                "schema": {
127
-                  "$ref": "#/components/schemas/LoginResult"
128
-                }
129
-              }
130
-            }
131
-          },
132
-          "401": {
133
-            "description": "Error",
134
-            "content": {
135
-              "application/json": {
136
-                "schema": {
137
-                  "$ref": "#/components/schemas/ErrorResponse"
138
-                }
139
-              }
140
-            }
141
-          }
142
-        },
143
-        "x-codegen-request-body-name": "body"
144
-      },
145
-      "x-swagger-router-controller": "api"
146
-    },
147
-    "/api/notices": {
148
-      "summary": "getNotices",
149
-      "description": "NoticeIconItem",
150
-      "get": {
151
-        "tags": ["api"],
152
-        "operationId": "getNotices",
153
-        "responses": {
154
-          "200": {
155
-            "description": "Success",
156
-            "content": {
157
-              "application/json": {
158
-                "schema": {
159
-                  "$ref": "#/components/schemas/NoticeIconList"
160
-                }
161
-              }
162
-            }
163
-          }
164
-        }
165
-      }
166
-    },
167
-    "/api/rule": {
168
-      "get": {
169
-        "tags": ["rule"],
170
-        "description": "获取规则列表",
171
-        "operationId": "rule",
172
-        "parameters": [
173
-          {
174
-            "name": "current",
175
-            "in": "query",
176
-            "description": "当前的页码",
177
-            "schema": {
178
-              "type": "number"
179
-            }
180
-          },
181
-          {
182
-            "name": "pageSize",
183
-            "in": "query",
184
-            "description": "页面的容量",
185
-            "schema": {
186
-              "type": "number"
187
-            }
188
-          }
189
-        ],
190
-        "responses": {
191
-          "200": {
192
-            "description": "Success",
193
-            "content": {
194
-              "application/json": {
195
-                "schema": {
196
-                  "$ref": "#/components/schemas/RuleList"
197
-                }
198
-              }
199
-            }
200
-          },
201
-          "401": {
202
-            "description": "Error",
203
-            "content": {
204
-              "application/json": {
205
-                "schema": {
206
-                  "$ref": "#/components/schemas/ErrorResponse"
207
-                }
208
-              }
209
-            }
210
-          }
211
-        }
212
-      },
213
-      "post": {
214
-        "tags": ["rule"],
215
-        "description": "新建规则",
216
-        "operationId": "addRule",
217
-        "responses": {
218
-          "200": {
219
-            "description": "Success",
220
-            "content": {
221
-              "application/json": {
222
-                "schema": {
223
-                  "$ref": "#/components/schemas/RuleListItem"
224
-                }
225
-              }
226
-            }
227
-          },
228
-          "401": {
229
-            "description": "Error",
230
-            "content": {
231
-              "application/json": {
232
-                "schema": {
233
-                  "$ref": "#/components/schemas/ErrorResponse"
234
-                }
235
-              }
236
-            }
237
-          }
238
-        }
239
-      },
240
-      "put": {
241
-        "tags": ["rule"],
242
-        "description": "新建规则",
243
-        "operationId": "updateRule",
244
-        "responses": {
245
-          "200": {
246
-            "description": "Success",
247
-            "content": {
248
-              "application/json": {
249
-                "schema": {
250
-                  "$ref": "#/components/schemas/RuleListItem"
251
-                }
252
-              }
253
-            }
254
-          },
255
-          "401": {
256
-            "description": "Error",
257
-            "content": {
258
-              "application/json": {
259
-                "schema": {
260
-                  "$ref": "#/components/schemas/ErrorResponse"
261
-                }
262
-              }
263
-            }
264
-          }
265
-        }
266
-      },
267
-      "delete": {
268
-        "tags": ["rule"],
269
-        "description": "删除规则",
270
-        "operationId": "removeRule",
271
-        "responses": {
272
-          "200": {
273
-            "description": "Success",
274
-            "content": {
275
-              "application/json": {
276
-                "schema": {
277
-                  "type": "object"
278
-                }
279
-              }
280
-            }
281
-          },
282
-          "401": {
283
-            "description": "Error",
284
-            "content": {
285
-              "application/json": {
286
-                "schema": {
287
-                  "$ref": "#/components/schemas/ErrorResponse"
288
-                }
289
-              }
290
-            }
291
-          }
292
-        }
293
-      },
294
-      "x-swagger-router-controller": "api"
295
-    },
296
-    "/swagger": {
297
-      "x-swagger-pipe": "swagger_raw"
298
-    }
299
-  },
300
-  "components": {
301
-    "schemas": {
302
-      "CurrentUser": {
303
-        "type": "object",
304
-        "properties": {
305
-          "name": {
306
-            "type": "string"
307
-          },
308
-          "avatar": {
309
-            "type": "string"
310
-          },
311
-          "userid": {
312
-            "type": "string"
313
-          },
314
-          "email": {
315
-            "type": "string"
316
-          },
317
-          "signature": {
318
-            "type": "string"
319
-          },
320
-          "title": {
321
-            "type": "string"
322
-          },
323
-          "group": {
324
-            "type": "string"
325
-          },
326
-          "tags": {
327
-            "type": "array",
328
-            "items": {
329
-              "type": "object",
330
-              "properties": {
331
-                "key": {
332
-                  "type": "string"
333
-                },
334
-                "label": {
335
-                  "type": "string"
336
-                }
337
-              }
338
-            }
339
-          },
340
-          "notifyCount": {
341
-            "type": "integer",
342
-            "format": "int32"
343
-          },
344
-          "unreadCount": {
345
-            "type": "integer",
346
-            "format": "int32"
347
-          },
348
-          "country": {
349
-            "type": "string"
350
-          },
351
-          "access": {
352
-            "type": "string"
353
-          },
354
-          "geographic": {
355
-            "type": "object",
356
-            "properties": {
357
-              "province": {
358
-                "type": "object",
359
-                "properties": {
360
-                  "label": {
361
-                    "type": "string"
362
-                  },
363
-                  "key": {
364
-                    "type": "string"
365
-                  }
366
-                }
367
-              },
368
-              "city": {
369
-                "type": "object",
370
-                "properties": {
371
-                  "label": {
372
-                    "type": "string"
373
-                  },
374
-                  "key": {
375
-                    "type": "string"
376
-                  }
377
-                }
378
-              }
379
-            }
380
-          },
381
-          "address": {
382
-            "type": "string"
383
-          },
384
-          "phone": {
385
-            "type": "string"
386
-          }
387
-        }
388
-      },
389
-      "LoginResult": {
390
-        "type": "object",
391
-        "properties": {
392
-          "status": {
393
-            "type": "string"
394
-          },
395
-          "type": {
396
-            "type": "string"
397
-          },
398
-          "currentAuthority": {
399
-            "type": "string"
400
-          }
401
-        }
402
-      },
403
-      "PageParams": {
404
-        "type": "object",
405
-        "properties": {
406
-          "current": {
407
-            "type": "number"
408
-          },
409
-          "pageSize": {
410
-            "type": "number"
411
-          }
412
-        }
413
-      },
414
-      "RuleListItem": {
415
-        "type": "object",
416
-        "properties": {
417
-          "key": {
418
-            "type": "integer",
419
-            "format": "int32"
420
-          },
421
-          "disabled": {
422
-            "type": "boolean"
423
-          },
424
-          "href": {
425
-            "type": "string"
426
-          },
427
-          "avatar": {
428
-            "type": "string"
429
-          },
430
-          "name": {
431
-            "type": "string"
432
-          },
433
-          "owner": {
434
-            "type": "string"
435
-          },
436
-          "desc": {
437
-            "type": "string"
438
-          },
439
-          "callNo": {
440
-            "type": "integer",
441
-            "format": "int32"
442
-          },
443
-          "status": {
444
-            "type": "integer",
445
-            "format": "int32"
446
-          },
447
-          "updatedAt": {
448
-            "type": "string",
449
-            "format": "datetime"
450
-          },
451
-          "createdAt": {
452
-            "type": "string",
453
-            "format": "datetime"
454
-          },
455
-          "progress": {
456
-            "type": "integer",
457
-            "format": "int32"
458
-          }
459
-        }
460
-      },
461
-      "RuleList": {
462
-        "type": "object",
463
-        "properties": {
464
-          "data": {
465
-            "type": "array",
466
-            "items": {
467
-              "$ref": "#/components/schemas/RuleListItem"
468
-            }
469
-          },
470
-          "total": {
471
-            "type": "integer",
472
-            "description": "列表的内容总数",
473
-            "format": "int32"
474
-          },
475
-          "success": {
476
-            "type": "boolean"
477
-          }
478
-        }
479
-      },
480
-      "FakeCaptcha": {
481
-        "type": "object",
482
-        "properties": {
483
-          "code": {
484
-            "type": "integer",
485
-            "format": "int32"
486
-          },
487
-          "status": {
488
-            "type": "string"
489
-          }
490
-        }
491
-      },
492
-      "LoginParams": {
493
-        "type": "object",
494
-        "properties": {
495
-          "username": {
496
-            "type": "string"
497
-          },
498
-          "password": {
499
-            "type": "string"
500
-          },
501
-          "autoLogin": {
502
-            "type": "boolean"
503
-          },
504
-          "type": {
505
-            "type": "string"
506
-          }
507
-        }
508
-      },
509
-      "ErrorResponse": {
510
-        "required": ["errorCode"],
511
-        "type": "object",
512
-        "properties": {
513
-          "errorCode": {
514
-            "type": "string",
515
-            "description": "业务约定的错误码"
516
-          },
517
-          "errorMessage": {
518
-            "type": "string",
519
-            "description": "业务上的错误信息"
520
-          },
521
-          "success": {
522
-            "type": "boolean",
523
-            "description": "业务上的请求是否成功"
524
-          }
525
-        }
526
-      },
527
-      "NoticeIconList": {
528
-        "type": "object",
529
-        "properties": {
530
-          "data": {
531
-            "type": "array",
532
-            "items": {
533
-              "$ref": "#/components/schemas/NoticeIconItem"
534
-            }
535
-          },
536
-          "total": {
537
-            "type": "integer",
538
-            "description": "列表的内容总数",
539
-            "format": "int32"
540
-          },
541
-          "success": {
542
-            "type": "boolean"
543
-          }
544
-        }
545
-      },
546
-      "NoticeIconItemType": {
547
-        "title": "NoticeIconItemType",
548
-        "description": "已读未读列表的枚举",
549
-        "type": "string",
550
-        "properties": {},
551
-        "enum": ["notification", "message", "event"]
552
-      },
553
-      "NoticeIconItem": {
554
-        "type": "object",
555
-        "properties": {
556
-          "id": {
557
-            "type": "string"
558
-          },
559
-          "extra": {
560
-            "type": "string",
561
-            "format": "any"
562
-          },
563
-          "key": { "type": "string" },
564
-          "read": {
565
-            "type": "boolean"
566
-          },
567
-          "avatar": {
568
-            "type": "string"
569
-          },
570
-          "title": {
571
-            "type": "string"
572
-          },
573
-          "status": {
574
-            "type": "string"
575
-          },
576
-          "datetime": {
577
-            "type": "string",
578
-            "format": "date"
579
-          },
580
-          "description": {
581
-            "type": "string"
582
-          },
583
-          "type": {
584
-            "extensions": {
585
-              "x-is-enum": true
586
-            },
587
-            "$ref": "#/components/schemas/NoticeIconItemType"
588
-          }
589
-        }
590
-      }
591
-    }
592
-  }
593
-}

+ 0
- 35
config/proxy.js Zobrazit soubor

@@ -1,35 +0,0 @@
1
-/**
2
- * 在生产环境 代理是无法生效的,所以这里没有生产环境的配置
3
- * -------------------------------
4
- * The agent cannot take effect in the production environment
5
- * so there is no configuration of the production environment
6
- * For details, please see
7
- * https://pro.ant.design/docs/deploy
8
- */
9
-export default {
10
-  dev: {
11
-    // localhost:8000/api/** -> https://preview.pro.ant.design/api/**
12
-    '/api/': {
13
-      // 要代理的地址
14
-      //http://192.168.89.147:8087
15
-      target: 'http://192.168.89.147:8087',
16
-      // 配置了这个可以从 http 代理到 https
17
-      // 依赖 origin 的功能可能需要这个,比如 cookie
18
-      changeOrigin: true,
19
-    },
20
-  },
21
-  test: {
22
-    '/api/': {
23
-      target: 'https://proapi.azurewebsites.net',
24
-      changeOrigin: true,
25
-      pathRewrite: { '^': '' },
26
-    },
27
-  },
28
-  pre: {
29
-    '/api/': {
30
-      target: 'your pre url',
31
-      changeOrigin: true,
32
-      pathRewrite: { '^': '' },
33
-    },
34
-  },
35
-};

+ 0
- 148
config/routes.js Zobrazit soubor

@@ -1,148 +0,0 @@
1
-export default [
2
-  {
3
-    path: '/user',
4
-    layout: false,
5
-    routes: [
6
-      {
7
-        name: 'login',
8
-        path: '/user/login',
9
-        component: './User/Login',
10
-      },
11
-      {
12
-        component: './404',
13
-      },
14
-    ],
15
-  },
16
-  // {
17
-  //   path: '/welcome',
18
-  //   name: 'welcome',
19
-  //   icon: 'smile',
20
-  //   component: './Welcome',
21
-  // },
22
-  {
23
-    path: '/',
24
-    redirect: '/rotationChart/list',
25
-  },
26
-  {
27
-    path: '/rotationChart',
28
-    name: '轮播图管理',
29
-    icon: 'picCenter',
30
-    routes: [
31
-      {
32
-        path: '/rotationChart/list',
33
-        name: '轮播图管理',
34
-        component: './rotationChart/list',
35
-      },
36
-    ],
37
-  },
38
-  {
39
-    path: '/rotationChart/add',
40
-    name: '轮播图新增',
41
-    hideInMenu: true,
42
-    component: './rotationChart/edit',
43
-  },
44
-  {
45
-    path: '/rotationChart/edit',
46
-    name: '轮播图编辑',
47
-    hideInMenu: true,
48
-    component: './rotationChart/edit',
49
-  },
50
-  // {
51
-  //   path: '/monitor',
52
-  //   name: '监控管理',
53
-  //   icon: 'VideoCameraOutlined',
54
-  //   component: './monitor/index',
55
-  // },
56
-  {
57
-    path: '/dish/list',
58
-    name: '菜肴管理',
59
-    icon: 'star',
60
-    icon: 'VideoCameraOutlined',
61
-    component: './dish/list',
62
-  },
63
-  {
64
-    path: '/dish/add',
65
-    name: '菜肴详情',
66
-    icon: 'smile',
67
-    hideInMenu: true,
68
-    component: './dish/edit',
69
-  },
70
-  {
71
-    path: '/dish/edit',
72
-    name: '菜肴修改',
73
-    hideInMenu: true,
74
-    component: './dish/edit',
75
-  },
76
-  {
77
-    path: '/package/list',
78
-    name: '套餐管理',
79
-    icon: 'shopping',
80
-    component: './package/index',
81
-  },
82
-  {
83
-    path: '/guaranteeTask/list',
84
-    name: '任务管理',
85
-    icon: 'borderBottom',
86
-    component: './guaranteeTask/index',
87
-  },
88
-  {
89
-    path: '/guaranteeTask/edit',
90
-    name: '任务详情',
91
-    icon: 'borderBottom',
92
-    hideInMenu: true,
93
-    component: './guaranteeTask/Edit/index',
94
-  },
95
-  {
96
-    path: '/stock/list',
97
-    name: '库存管理',
98
-    icon: 'appstore',
99
-    component: './stock/list',
100
-  },
101
-  {
102
-    path: '/stock/add',
103
-    name: '库存新增',
104
-    hideInMenu: true,
105
-    component: './stock/edit',
106
-  },
107
-
108
-  {
109
-    path: '/stock/edit',
110
-    name: '库存详细',
111
-    hideInMenu: true,
112
-    component: './stock/edit',
113
-  },
114
-  {
115
-    path: '/stock/outAndIn',
116
-    name: '出入库管理',
117
-    hideInMenu: true,
118
-    component: './stock/outAndIn',
119
-  },
120
-  {
121
-    path: '/stockLog/list',
122
-    name: '库存日志',
123
-    icon: 'appstoreAdd',
124
-    component: './stock/stockLog',
125
-  },
126
-  {
127
-    path: '/stockClassification/list',
128
-    name: '库存分类',
129
-    icon: 'sortAscending',
130
-    component: './stockClassification/list',
131
-  },
132
-  {
133
-    path: '/stockClassification/edit',
134
-    name: '分类编辑',
135
-    hideInMenu: true,
136
-    component: './stockClassification/edit',
137
-  },
138
-  {
139
-    path: '/guaranteeTask/print',
140
-    name: '保障单打印',
141
-    hideInMenu: true,
142
-    layout: false,
143
-    component: './guaranteeTask/print/index',
144
-  },
145
-  {
146
-    component: './404',
147
-  },
148
-];

+ 13
- 0
index.html Zobrazit soubor

@@ -0,0 +1,13 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+  <head>
4
+    <meta charset="UTF-8" />
5
+    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+    <title>Vite + React</title>
8
+  </head>
9
+  <body>
10
+    <div id="root"></div>
11
+    <script type="module" src="/src/main.jsx"></script>
12
+  </body>
13
+</html>

+ 0
- 9
jest.config.js Zobrazit soubor

@@ -1,9 +0,0 @@
1
-module.exports = {
2
-  testURL: 'http://localhost:8000',
3
-  verbose: false,
4
-  extraSetupFiles: ['./tests/setupTests.js'],
5
-  globals: {
6
-    ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: false,
7
-    localStorage: null,
8
-  },
9
-};

+ 0
- 3
jsconfig.json Zobrazit soubor

@@ -1,8 +1,5 @@
1 1
 {
2 2
   "compilerOptions": {
3
-    "jsx": "react-jsx",
4
-    "emitDecoratorMetadata": true,
5
-    "experimentalDecorators": true,
6 3
     "baseUrl": ".",
7 4
     "paths": {
8 5
       "@/*": ["./src/*"]

+ 0
- 174
mock/listTableList.ts Zobrazit soubor

@@ -1,174 +0,0 @@
1
-import { Request, Response } from 'express';
2
-import moment from 'moment';
3
-import { parse } from 'url';
4
-
5
-// mock tableListDataSource
6
-const genList = (current: number, pageSize: number) => {
7
-  const tableListDataSource: API.RuleListItem[] = [];
8
-
9
-  for (let i = 0; i < pageSize; i += 1) {
10
-    const index = (current - 1) * 10 + i;
11
-    tableListDataSource.push({
12
-      key: index,
13
-      disabled: i % 6 === 0,
14
-      href: 'https://ant.design',
15
-      avatar: [
16
-        'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
17
-        'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
18
-      ][i % 2],
19
-      name: `TradeCode ${index}`,
20
-      owner: '曲丽丽',
21
-      desc: '这是一段描述',
22
-      callNo: Math.floor(Math.random() * 1000),
23
-      status: Math.floor(Math.random() * 10) % 4,
24
-      updatedAt: moment().format('YYYY-MM-DD'),
25
-      createdAt: moment().format('YYYY-MM-DD'),
26
-      progress: Math.ceil(Math.random() * 100),
27
-    });
28
-  }
29
-  tableListDataSource.reverse();
30
-  return tableListDataSource;
31
-};
32
-
33
-let tableListDataSource = genList(1, 100);
34
-
35
-function getRule(req: Request, res: Response, u: string) {
36
-  let realUrl = u;
37
-  if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
38
-    realUrl = req.url;
39
-  }
40
-  const { current = 1, pageSize = 10 } = req.query;
41
-  const params = parse(realUrl, true).query as unknown as API.PageParams &
42
-    API.RuleListItem & {
43
-      sorter: any;
44
-      filter: any;
45
-    };
46
-
47
-  let dataSource = [...tableListDataSource].slice(
48
-    ((current as number) - 1) * (pageSize as number),
49
-    (current as number) * (pageSize as number),
50
-  );
51
-  if (params.sorter) {
52
-    const sorter = JSON.parse(params.sorter);
53
-    dataSource = dataSource.sort((prev, next) => {
54
-      let sortNumber = 0;
55
-      Object.keys(sorter).forEach((key) => {
56
-        if (sorter[key] === 'descend') {
57
-          if (prev[key] - next[key] > 0) {
58
-            sortNumber += -1;
59
-          } else {
60
-            sortNumber += 1;
61
-          }
62
-          return;
63
-        }
64
-        if (prev[key] - next[key] > 0) {
65
-          sortNumber += 1;
66
-        } else {
67
-          sortNumber += -1;
68
-        }
69
-      });
70
-      return sortNumber;
71
-    });
72
-  }
73
-  if (params.filter) {
74
-    const filter = JSON.parse(params.filter as any) as {
75
-      [key: string]: string[];
76
-    };
77
-    if (Object.keys(filter).length > 0) {
78
-      dataSource = dataSource.filter((item) => {
79
-        return Object.keys(filter).some((key) => {
80
-          if (!filter[key]) {
81
-            return true;
82
-          }
83
-          if (filter[key].includes(`${item[key]}`)) {
84
-            return true;
85
-          }
86
-          return false;
87
-        });
88
-      });
89
-    }
90
-  }
91
-
92
-  if (params.name) {
93
-    dataSource = dataSource.filter((data) => data?.name?.includes(params.name || ''));
94
-  }
95
-  const result = {
96
-    data: dataSource,
97
-    total: tableListDataSource.length,
98
-    success: true,
99
-    pageSize,
100
-    current: parseInt(`${params.current}`, 10) || 1,
101
-  };
102
-
103
-  return res.json(result);
104
-}
105
-
106
-function postRule(req: Request, res: Response, u: string, b: Request) {
107
-  let realUrl = u;
108
-  if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
109
-    realUrl = req.url;
110
-  }
111
-
112
-  const body = (b && b.body) || req.body;
113
-  const { method, name, desc, key } = body;
114
-
115
-  switch (method) {
116
-    /* eslint no-case-declarations:0 */
117
-    case 'delete':
118
-      tableListDataSource = tableListDataSource.filter((item) => key.indexOf(item.key) === -1);
119
-      break;
120
-    case 'post':
121
-      (() => {
122
-        const i = Math.ceil(Math.random() * 10000);
123
-        const newRule: API.RuleListItem = {
124
-          key: tableListDataSource.length,
125
-          href: 'https://ant.design',
126
-          avatar: [
127
-            'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
128
-            'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
129
-          ][i % 2],
130
-          name,
131
-          owner: '曲丽丽',
132
-          desc,
133
-          callNo: Math.floor(Math.random() * 1000),
134
-          status: Math.floor(Math.random() * 10) % 2,
135
-          updatedAt: moment().format('YYYY-MM-DD'),
136
-          createdAt: moment().format('YYYY-MM-DD'),
137
-          progress: Math.ceil(Math.random() * 100),
138
-        };
139
-        tableListDataSource.unshift(newRule);
140
-        return res.json(newRule);
141
-      })();
142
-      return;
143
-
144
-    case 'update':
145
-      (() => {
146
-        let newRule = {};
147
-        tableListDataSource = tableListDataSource.map((item) => {
148
-          if (item.key === key) {
149
-            newRule = { ...item, desc, name };
150
-            return { ...item, desc, name };
151
-          }
152
-          return item;
153
-        });
154
-        return res.json(newRule);
155
-      })();
156
-      return;
157
-    default:
158
-      break;
159
-  }
160
-
161
-  const result = {
162
-    list: tableListDataSource,
163
-    pagination: {
164
-      total: tableListDataSource.length,
165
-    },
166
-  };
167
-
168
-  res.json(result);
169
-}
170
-
171
-export default {
172
-  'GET /api/rule': getRule,
173
-  'POST /api/rule': postRule,
174
-};

+ 0
- 107
mock/notices.ts Zobrazit soubor

@@ -1,107 +0,0 @@
1
-import { Request, Response } from 'express';
2
-
3
-const getNotices = (req: Request, res: Response) => {
4
-  res.json({
5
-    data: [
6
-      {
7
-        id: '000000001',
8
-        avatar: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/MSbDR4FR2MUAAAAAAAAAAAAAFl94AQBr',
9
-        title: '你收到了 14 份新周报',
10
-        datetime: '2017-08-09',
11
-        type: 'notification',
12
-      },
13
-      {
14
-        id: '000000002',
15
-        avatar: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/hX-PTavYIq4AAAAAAAAAAAAAFl94AQBr',
16
-        title: '你推荐的 曲妮妮 已通过第三轮面试',
17
-        datetime: '2017-08-08',
18
-        type: 'notification',
19
-      },
20
-      {
21
-        id: '000000003',
22
-        avatar: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/jHX5R5l3QjQAAAAAAAAAAAAAFl94AQBr',
23
-        title: '这种模板可以区分多种通知类型',
24
-        datetime: '2017-08-07',
25
-        read: true,
26
-        type: 'notification',
27
-      },
28
-      {
29
-        id: '000000004',
30
-        avatar: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/Wr4mQqx6jfwAAAAAAAAAAAAAFl94AQBr',
31
-        title: '左侧图标用于区分不同的类型',
32
-        datetime: '2017-08-07',
33
-        type: 'notification',
34
-      },
35
-      {
36
-        id: '000000005',
37
-        avatar: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/Mzj_TbcWUj4AAAAAAAAAAAAAFl94AQBr',
38
-        title: '内容不要超过两行字,超出时自动截断',
39
-        datetime: '2017-08-07',
40
-        type: 'notification',
41
-      },
42
-      {
43
-        id: '000000006',
44
-        avatar: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/eXLzRbPqQE4AAAAAAAAAAAAAFl94AQBr',
45
-        title: '曲丽丽 评论了你',
46
-        description: '描述信息描述信息描述信息',
47
-        datetime: '2017-08-07',
48
-        type: 'message',
49
-        clickClose: true,
50
-      },
51
-      {
52
-        id: '000000007',
53
-        avatar: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/w5mRQY2AmEEAAAAAAAAAAAAAFl94AQBr',
54
-        title: '朱偏右 回复了你',
55
-        description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
56
-        datetime: '2017-08-07',
57
-        type: 'message',
58
-        clickClose: true,
59
-      },
60
-      {
61
-        id: '000000008',
62
-        avatar: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/wPadR5M9918AAAAAAAAAAAAAFl94AQBr',
63
-        title: '标题',
64
-        description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
65
-        datetime: '2017-08-07',
66
-        type: 'message',
67
-        clickClose: true,
68
-      },
69
-      {
70
-        id: '000000009',
71
-        title: '任务名称',
72
-        description: '任务需要在 2017-01-12 20:00 前启动',
73
-        extra: '未开始',
74
-        status: 'todo',
75
-        type: 'event',
76
-      },
77
-      {
78
-        id: '000000010',
79
-        title: '第三方紧急代码变更',
80
-        description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
81
-        extra: '马上到期',
82
-        status: 'urgent',
83
-        type: 'event',
84
-      },
85
-      {
86
-        id: '000000011',
87
-        title: '信息安全考试',
88
-        description: '指派竹尔于 2017-01-09 前完成更新并发布',
89
-        extra: '已耗时 8 天',
90
-        status: 'doing',
91
-        type: 'event',
92
-      },
93
-      {
94
-        id: '000000012',
95
-        title: 'ABCD 版本发布',
96
-        description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务',
97
-        extra: '进行中',
98
-        status: 'processing',
99
-        type: 'event',
100
-      },
101
-    ],
102
-  });
103
-};
104
-
105
-export default {
106
-  'GET /api/notices': getNotices,
107
-};

+ 0
- 5
mock/route.ts Zobrazit soubor

@@ -1,5 +0,0 @@
1
-export default {
2
-  '/api/auth_routes': {
3
-    '/form/advanced-form': { authority: ['admin', 'user'] },
4
-  },
5
-};

+ 0
- 203
mock/user.ts Zobrazit soubor

@@ -1,203 +0,0 @@
1
-import { Request, Response } from 'express';
2
-
3
-const waitTime = (time: number = 100) => {
4
-  return new Promise((resolve) => {
5
-    setTimeout(() => {
6
-      resolve(true);
7
-    }, time);
8
-  });
9
-};
10
-
11
-async function getFakeCaptcha(req: Request, res: Response) {
12
-  await waitTime(2000);
13
-  return res.json('captcha-xxx');
14
-}
15
-
16
-const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION } = process.env;
17
-
18
-/**
19
- * 当前用户的权限,如果为空代表没登录
20
- * current user access, if is '', user need login
21
- * 如果是 pro 的预览,默认是有权限的
22
- */
23
-let access = ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site' ? 'admin' : '';
24
-
25
-const getAccess = () => {
26
-  return access;
27
-};
28
-
29
-// 代码中会兼容本地 service mock 以及部署站点的静态数据
30
-export default {
31
-  // 支持值为 Object 和 Array
32
-  'GET /api/currentUser': (req: Request, res: Response) => {
33
-    if (!getAccess()) {
34
-      res.status(401).send({
35
-        data: {
36
-          isLogin: false,
37
-        },
38
-        errorCode: '401',
39
-        errorMessage: '请先登录!',
40
-        success: true,
41
-      });
42
-      return;
43
-    }
44
-    res.send({
45
-      success: true,
46
-      data: {
47
-        name: 'Serati Ma',
48
-        avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
49
-        userid: '00000001',
50
-        email: 'antdesign@alipay.com',
51
-        signature: '海纳百川,有容乃大',
52
-        title: '交互专家',
53
-        group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED',
54
-        tags: [
55
-          {
56
-            key: '0',
57
-            label: '很有想法的',
58
-          },
59
-          {
60
-            key: '1',
61
-            label: '专注设计',
62
-          },
63
-          {
64
-            key: '2',
65
-            label: '辣~',
66
-          },
67
-          {
68
-            key: '3',
69
-            label: '大长腿',
70
-          },
71
-          {
72
-            key: '4',
73
-            label: '川妹子',
74
-          },
75
-          {
76
-            key: '5',
77
-            label: '海纳百川',
78
-          },
79
-        ],
80
-        notifyCount: 12,
81
-        unreadCount: 11,
82
-        country: 'China',
83
-        access: getAccess(),
84
-        geographic: {
85
-          province: {
86
-            label: '浙江省',
87
-            key: '330000',
88
-          },
89
-          city: {
90
-            label: '杭州市',
91
-            key: '330100',
92
-          },
93
-        },
94
-        address: '西湖区工专路 77 号',
95
-        phone: '0752-268888888',
96
-      },
97
-    });
98
-  },
99
-  // GET POST 可省略
100
-  'GET /api/users': [
101
-    {
102
-      key: '1',
103
-      name: 'John Brown',
104
-      age: 32,
105
-      address: 'New York No. 1 Lake Park',
106
-    },
107
-    {
108
-      key: '2',
109
-      name: 'Jim Green',
110
-      age: 42,
111
-      address: 'London No. 1 Lake Park',
112
-    },
113
-    {
114
-      key: '3',
115
-      name: 'Joe Black',
116
-      age: 32,
117
-      address: 'Sidney No. 1 Lake Park',
118
-    },
119
-  ],
120
-  'POST /api/login/account': async (req: Request, res: Response) => {
121
-    const { password, username, type } = req.body;
122
-    await waitTime(2000);
123
-    if (password === '1' && username === '1') {
124
-      res.send({
125
-        status: 'ok',
126
-        type,
127
-        currentAuthority: 'admin',
128
-      });
129
-      access = 'admin';
130
-      return;
131
-    }
132
-    if (password === 'ant.design' && username === 'user') {
133
-      res.send({
134
-        status: 'ok',
135
-        type,
136
-        currentAuthority: 'user',
137
-      });
138
-      access = 'user';
139
-      return;
140
-    }
141
-    if (type === 'mobile') {
142
-      res.send({
143
-        status: 'ok',
144
-        type,
145
-        currentAuthority: 'admin',
146
-      });
147
-      access = 'admin';
148
-      return;
149
-    }
150
-
151
-    res.send({
152
-      status: 'error',
153
-      type,
154
-      currentAuthority: 'guest',
155
-    });
156
-    access = 'guest';
157
-  },
158
-  'POST /api/login/outLogin': (req: Request, res: Response) => {
159
-    access = '';
160
-    res.send({ data: {}, success: true });
161
-  },
162
-  'POST /api/register': (req: Request, res: Response) => {
163
-    res.send({ status: 'ok', currentAuthority: 'user', success: true });
164
-  },
165
-  'GET /api/500': (req: Request, res: Response) => {
166
-    res.status(500).send({
167
-      timestamp: 1513932555104,
168
-      status: 500,
169
-      error: 'error',
170
-      message: 'error',
171
-      path: '/base/category/list',
172
-    });
173
-  },
174
-  'GET /api/404': (req: Request, res: Response) => {
175
-    res.status(404).send({
176
-      timestamp: 1513932643431,
177
-      status: 404,
178
-      error: 'Not Found',
179
-      message: 'No message available',
180
-      path: '/base/category/list/2121212',
181
-    });
182
-  },
183
-  'GET /api/403': (req: Request, res: Response) => {
184
-    res.status(403).send({
185
-      timestamp: 1513932555104,
186
-      status: 403,
187
-      error: 'Forbidden',
188
-      message: 'Forbidden',
189
-      path: '/base/category/list',
190
-    });
191
-  },
192
-  'GET /api/401': (req: Request, res: Response) => {
193
-    res.status(401).send({
194
-      timestamp: 1513932555104,
195
-      status: 401,
196
-      error: 'Unauthorized',
197
-      message: 'Unauthorized',
198
-      path: '/base/category/list',
199
-    });
200
-  },
201
-
202
-  'GET  /api/login/captcha': getFakeCaptcha,
203
-};

+ 2310
- 0
package-lock.json
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 24
- 111
package.json Zobrazit soubor

@@ -1,122 +1,35 @@
1 1
 {
2
-  "name": "ant-design-pro",
3
-  "version": "6.0.0-beta.1",
2
+  "name": "vite-project",
4 3
   "private": true,
5
-  "description": "An out-of-box UI solution for enterprise applications",
4
+  "version": "0.0.0",
5
+  "type": "module",
6 6
   "scripts": {
7
-    "analyze": "cross-env ANALYZE=1 max build",
8
-    "build": "max build",
9
-    "deploy": "npm run build && npm run gh-pages",
10
-    "dev": "npm run start:dev",
11
-    "gh-pages": "gh-pages -d dist",
12
-    "i18n-remove": "pro i18n-remove --locale=zh-CN --write",
13
-    "postinstall": "max setup",
14
-    "lint": "npm run lint:js && npm run lint:prettier && npm run tsc",
15
-    "lint-staged": "lint-staged",
16
-    "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
17
-    "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src ",
18
-    "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
19
-    "lint:prettier": "prettier -c --write \"src/**/*\" --end-of-line auto",
20
-    "openapi": "max openapi",
21
-    "playwright": "playwright install && playwright test",
22
-    "prepare": "husky install",
23
-    "prettier": "prettier -c --write \"src/**/*\"",
24
-    "serve": "umi-serve",
25
-    "start": "cross-env UMI_ENV=dev max dev",
26
-    "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev",
27
-    "start:no-mock": "cross-env MOCK=none UMI_ENV=dev max dev",
28
-    "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev",
29
-    "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev",
30
-    "test": "max test",
31
-    "test:component": "max test ./src/components",
32
-    "test:e2e": "node ./tests/run-tests.js",
33
-    "tsc": "tsc --noEmit"
7
+    "dev": "vite",
8
+    "build": "vite build",
9
+    "preview": "vite preview"
34 10
   },
35
-  "lint-staged": {
36
-    "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js",
37
-    "**/*.{js,jsx,tsx,ts,less,md,json}": [
38
-      "prettier --write"
39
-    ]
40
-  },
41
-  "browserslist": [
42
-    "> 1%",
43
-    "last 2 versions",
44
-    "not ie <= 10"
45
-  ],
46 11
   "dependencies": {
47 12
     "@ant-design/icons": "^4.7.0",
48
-    "@ant-design/pro-components": "^2.3.16",
49
-    "@umijs/route-utils": "^2.1.3",
50
-    "antd": "^4.20.0",
51
-    "classnames": "^2.3.0",
52
-    "lodash": "^4.17.0",
13
+    "@ant-design/pro-components": "^2.3.13",
14
+    "@zjxpcyc/react-tiny-store": "^2.0.1",
15
+    "antd": "^4.23.4",
16
+    "axios": "^1.1.2",
17
+    "classnames": "^2.3.2",
18
+    "echarts": "^5.4.0",
53 19
     "md5": "^2.3.0",
54
-    "moment": "^2.29.0",
55
-    "omit.js": "^2.0.2",
56
-    "rc-menu": "^9.1.0",
57
-    "rc-util": "^5.16.0",
58
-    "react": "^17.0.0",
59
-    "react-dev-inspector": "^1.7.0",
60
-    "react-dom": "^17.0.0",
61
-    "react-helmet-async": "^1.2.0"
20
+    "moment": "^2.29.4",
21
+    "react": "18.1.0",
22
+    "react-dom": "18.1.0",
23
+    "react-helmet": "^6.1.0",
24
+    "react-router-dom": "^6.4.2",
25
+    "react-transition-group": "^4.4.5"
62 26
   },
63 27
   "devDependencies": {
64
-    "@ant-design/pro-cli": "^2.1.0",
65
-    "@playwright/test": "^1.17.0",
66
-    "@types/classnames": "^2.3.1",
67
-    "@types/express": "^4.17.0",
68
-    "@types/history": "^4.7.0",
69
-    "@types/lodash": "^4.14.0",
70
-    "@types/react": "^17.0.0",
71
-    "@types/react-dom": "^17.0.0",
72
-    "@types/react-helmet": "^6.1.0",
73
-    "@umijs/fabric": "^2.11.1",
74
-    "@umijs/max": "^4.0.0-rc.22",
75
-    "@umijs/openapi": "^1.3.0",
76
-    "cross-env": "^7.0.0",
77
-    "cross-port-killer": "^1.3.0",
78
-    "detect-installer": "^1.0.0",
79
-    "eslint": "^7.32.0",
80
-    "gh-pages": "^3.2.0",
81
-    "husky": "^7.0.4",
82
-    "lint-staged": "^10.0.0",
83
-    "mockjs": "^1.1.0",
84
-    "prettier": "^2.5.0",
85
-    "swagger-ui-dist": "^4.12.0",
86
-    "typescript": "^4.5.0",
87
-    "umi-presets-pro": "^1.0.1",
88
-    "umi-serve": "^1.9.10"
89
-  },
90
-  "engines": {
91
-    "node": ">=12.0.0"
92
-  },
93
-  "create-umi": {
94
-    "ignoreScript": [
95
-      "docker*",
96
-      "functions*",
97
-      "site",
98
-      "generateMock"
99
-    ],
100
-    "ignoreDependencies": [
101
-      "netlify*",
102
-      "serverless"
103
-    ],
104
-    "ignore": [
105
-      ".dockerignore",
106
-      ".git",
107
-      ".github",
108
-      ".gitpod.yml",
109
-      "CODE_OF_CONDUCT.md",
110
-      "Dockerfile",
111
-      "Dockerfile.*",
112
-      "lambda",
113
-      "LICENSE",
114
-      "netlify.toml",
115
-      "README.*.md",
116
-      "azure-pipelines.yml",
117
-      "docker",
118
-      "CNAME",
119
-      "create-umi"
120
-    ]
28
+    "@types/react": "^18.0.15",
29
+    "@types/react-dom": "^18.0.6",
30
+    "@vitejs/plugin-react": "^2.0.0",
31
+    "less": "^4.1.3",
32
+    "vite": "^3.0.0",
33
+    "vite-plugin-imp": "^2.2.0"
121 34
   }
122 35
 }

+ 0
- 22
playwright.config.ts Zobrazit soubor

@@ -1,22 +0,0 @@
1
-// playwright.config.ts
2
-import type { PlaywrightTestConfig } from '@playwright/test';
3
-import { devices } from '@playwright/test';
4
-
5
-const config: PlaywrightTestConfig = {
6
-  forbidOnly: !!process.env.CI,
7
-  retries: process.env.CI ? 2 : 0,
8
-  use: {
9
-    trace: 'on-first-retry',
10
-  },
11
-  projects: [
12
-    {
13
-      name: 'chromium',
14
-      use: { ...devices['Desktop Chrome'] },
15
-    },
16
-    {
17
-      name: 'firefox',
18
-      use: { ...devices['Desktop Firefox'] },
19
-    },
20
-  ],
21
-};
22
-export default config;

+ 3109
- 0
pnpm-lock.yaml
Diff nebyl zobrazen, protože je příliš veliký
Zobrazit soubor


+ 0
- 1
public/CNAME Zobrazit soubor

@@ -1 +0,0 @@
1
-preview.pro.ant.design

binární
public/favicon.ico Zobrazit soubor


binární
public/logo.png Zobrazit soubor


+ 1
- 0
public/vite.svg Zobrazit soubor

@@ -0,0 +1 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

+ 42
- 0
src/App.css Zobrazit soubor

@@ -0,0 +1,42 @@
1
+#root {
2
+  max-width: 1280px;
3
+  margin: 0 auto;
4
+  padding: 2rem;
5
+  text-align: center;
6
+}
7
+
8
+.logo {
9
+  height: 6em;
10
+  padding: 1.5em;
11
+  will-change: filter;
12
+}
13
+.logo:hover {
14
+  filter: drop-shadow(0 0 2em #646cffaa);
15
+}
16
+.logo.react:hover {
17
+  filter: drop-shadow(0 0 2em #61dafbaa);
18
+}
19
+
20
+
21
+@keyframes logo-spin {
22
+  from {
23
+    transform: rotate(0deg);
24
+  }
25
+  to {
26
+    transform: rotate(360deg);
27
+  }
28
+}
29
+
30
+@media (prefers-reduced-motion: no-preference) {
31
+  a:nth-of-type(2) .logo {
32
+    animation: logo-spin infinite 20s linear;
33
+  }
34
+}
35
+
36
+.card {
37
+  padding: 2em;
38
+}
39
+
40
+.read-the-docs {
41
+  color: #888;
42
+}

+ 0
- 9
src/access.ts Zobrazit soubor

@@ -1,9 +0,0 @@
1
-/**
2
- * @see https://umijs.org/zh-CN/plugins/plugin-access
3
- * */
4
-export default function access(initialState: { currentUser?: API.CurrentUser } | undefined) {
5
-  const { currentUser } = initialState ?? {};
6
-  return {
7
-    canAdmin: currentUser && currentUser.access === 'admin',
8
-  };
9
-}

+ 5
- 113
src/app.jsx Zobrazit soubor

@@ -1,118 +1,10 @@
1
-import { requestConfig } from '@/utils/request';
2
-import { Link } from 'umi';
3
-import { history } from '@umijs/max';
4
-import RightContent from '@/components/RightContent';
5
-import { SettingDrawer } from '@ant-design/pro-components';
6
-import { queryCurrentUser } from '@/services/api/user';
7
-import logoImg from '@/assets/images/logo.png';
8
-import defaultSettings from '../config/defaultSettings';
1
+import { useState } from 'react'
9 2
 
10
-const isDev = process.env.NODE_ENV === 'development';
11
-const loginPath = '/user/login';
12 3
 
13
-/**
14
- * @see  https://umijs.org/zh-CN/plugins/plugin-initial-state
15
- * */
4
+function App() {
5
+  const [count, setCount] = useState(0)
16 6
 
17
-export async function getInitialState() {
18
-  const fetchUserInfo = async () => {
19
-    try {
20
-      const msg = await queryCurrentUser();
21
-      return msg;
22
-    } catch (error) {
23
-      history.push(loginPath);
24
-    }
25
-    return undefined;
26
-  };
27
-
28
-  // 如果不是登录页面,执行
29
-  if (history.location.pathname !== loginPath) {
30
-    const currentUser = await fetchUserInfo();
31
-    return {
32
-      fetchUserInfo,
33
-      currentUser,
34
-      settings: defaultSettings,
35
-    };
36
-  }
37
-  return {
38
-    fetchUserInfo,
39
-    settings: defaultSettings,
40
-  };
7
+  return null;
41 8
 }
42 9
 
43
-// ProLayout 支持的api https://procomponents.ant.design/components/layout
44
-export const layout = ({ initialState, setInitialState }) => {
45
-  const cfg = {
46
-    rightContentRender: () => <RightContent />,
47
-    disableContentMargin: false,
48
-    token: {
49
-      sider: {
50
-        colorMenuBackground: '#001529',
51
-        colorBgMenuItemHover: '#fff',
52
-        colorBgMenuItemSelected: '#1890ff',
53
-        colorTextMenuActive: '#fff',
54
-        colorTextMenuSelected: '#fff',
55
-        colorTextMenuTitle: '#fff',
56
-        colorTextMenu: 'hsla(0,0%,100%,.65);',
57
-
58
-      },
59
-      header: {
60
-        colorBgHeader: '#0D267C',
61
-        colorHeaderTitle: '#fff',
62
-        colorTextMenuActive: '#fff',
63
-        colorTextMenu: '#fff',
64
-        colorTextMenuSelected: '#fff',
65
-        colorBgMenuItemHover: '#4276F5',
66
-        colorBgMenuItemSelected: '#4276F5',
67
-        colorTextRightActionsItem: '#fff',
68
-        heightLayoutHeader: 64,
69
-      }
70
-    },
71
-    // waterMarkProps: {
72
-    //   content: initialState?.currentUser?.name,
73
-    // },
74
-    // footerRender: () => <Footer />,
75
-    headerTitleRender: () => <Link to="/"><img src={logoImg} style={{ height: '42px' }} alt="" /></Link>,
76
-    onPageChange: () => {
77
-      const { location } = history;
78
-
79
-      // 如果没有登录,重定向到 login
80
-      if (!initialState?.currentUser && location.pathname !== loginPath) {
81
-        history.push(loginPath);
82
-      }
83
-    },
84
-    menuHeaderRender: undefined,
85
-    // 自定义 403 页面
86
-    // unAccessible: <div>unAccessible</div>,
87
-    // 增加一个 loading 的状态
88
-    childrenRender: (children, props) => {
89
-      // if (initialState?.loading) return <PageLoading />;
90
-      return (
91
-        <>
92
-          {children}
93
-          {/* {!props.location?.pathname?.includes('/login') && (
94
-            <SettingDrawer
95
-              disableUrlParams
96
-              enableDarkTheme
97
-              settings={initialState?.settings}
98
-              onSettingChange={(settings) => {
99
-                setInitialState((preInitialState) => ({
100
-                  ...preInitialState,
101
-                  settings,
102
-                }));
103
-              }}
104
-            />
105
-          )} */}
106
-        </>
107
-      );
108
-    },
109
-
110
-    ...initialState?.settings,
111
-  };
112
-
113
-  console.log(cfg)
114
-
115
-  return cfg;
116
-};
117
-
118
-export const request = requestConfig;
10
+export default App

+ 1
- 0
src/assets/react.svg Zobrazit soubor

@@ -0,0 +1 @@
1
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

+ 0
- 18
src/components/Footer/index.jsx Zobrazit soubor

@@ -1,18 +0,0 @@
1
-import { DefaultFooter } from '@ant-design/pro-components';
2
-
3
-const Footer = () => {
4
-  const defaultMessage = '南京云致';
5
-
6
-  const currentYear = new Date().getFullYear();
7
-
8
-  return (
9
-    <DefaultFooter
10
-      style={{
11
-        background: 'none',
12
-      }}
13
-      copyright={`${currentYear} ${defaultMessage}`}
14
-    />
15
-  );
16
-};
17
-
18
-export default Footer;

+ 0
- 16
src/components/HeaderDropdown/index.jsx Zobrazit soubor

@@ -1,16 +0,0 @@
1
-import { Dropdown } from 'antd';
2
-// import type { DropDownProps } from 'antd/es/dropdown';
3
-import classNames from 'classnames';
4
-import styles from './index.less';
5
-
6
-// export type HeaderDropdownProps = {
7
-//   overlayClassName?: string;
8
-//   overlay: React.ReactNode | (() => React.ReactNode) | any;
9
-//   placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter';
10
-// } & Omit<DropDownProps, 'overlay'>;
11
-
12
-const HeaderDropdown = ({ overlayClassName: cls, ...restProps }) => (
13
-  <Dropdown overlayClassName={classNames(styles.container, cls)} {...restProps} />
14
-);
15
-
16
-export default HeaderDropdown;

+ 0
- 16
src/components/HeaderDropdown/index.less Zobrazit soubor

@@ -1,16 +0,0 @@
1
-@import (reference) '~antd/es/style/themes/index';
2
-
3
-.container > * {
4
-  background-color: @popover-bg;
5
-  border-radius: 4px;
6
-  box-shadow: @shadow-1-down;
7
-}
8
-
9
-@media screen and (max-width: @screen-xs) {
10
-  .container {
11
-    width: 100% !important;
12
-  }
13
-  .container > * {
14
-    border-radius: 0 !important;
15
-  }
16
-}

+ 0
- 105
src/components/HeaderSearch/index.jsx Zobrazit soubor

@@ -1,105 +0,0 @@
1
-import { SearchOutlined } from '@ant-design/icons';
2
-// import type { InputRef } from 'antd';
3
-import { AutoComplete, Input } from 'antd';
4
-// import type { AutoCompleteProps } from 'antd/es/auto-complete';
5
-import classNames from 'classnames';
6
-import useMergedState from 'rc-util/es/hooks/useMergedState';
7
-import { useRef } from 'react';
8
-import styles from './index.less';
9
-
10
-// export type HeaderSearchProps = {
11
-//   onSearch?: (value?: string) => void;
12
-//   onChange?: (value?: string) => void;
13
-//   onVisibleChange?: (b: boolean) => void;
14
-//   className?: string;
15
-//   placeholder?: string;
16
-//   options: AutoCompleteProps['options'];
17
-//   defaultVisible?: boolean;
18
-//   visible?: boolean;
19
-//   defaultValue?: string;
20
-//   value?: string;
21
-// };
22
-
23
-const HeaderSearch = (props) => {
24
-  const {
25
-    className,
26
-    defaultValue,
27
-    onVisibleChange,
28
-    placeholder,
29
-    visible,
30
-    defaultVisible,
31
-    ...restProps
32
-  } = props;
33
-
34
-  const inputRef = useRef(null);
35
-
36
-  const [value, setValue] =
37
-    (useMergedState < string) |
38
-    (undefined >
39
-      (defaultValue,
40
-      {
41
-        value: props.value,
42
-        onChange: props.onChange,
43
-      }));
44
-
45
-  const [searchMode, setSearchMode] = useMergedState(defaultVisible ?? false, {
46
-    value: props.visible,
47
-    onChange: onVisibleChange,
48
-  });
49
-
50
-  const inputClass = classNames(styles.input, {
51
-    [styles.show]: searchMode,
52
-  });
53
-  return (
54
-    <div
55
-      className={classNames(className, styles.headerSearch)}
56
-      onClick={() => {
57
-        setSearchMode(true);
58
-        if (searchMode && inputRef.current) {
59
-          inputRef.current.focus();
60
-        }
61
-      }}
62
-      onTransitionEnd={({ propertyName }) => {
63
-        if (propertyName === 'width' && !searchMode) {
64
-          if (onVisibleChange) {
65
-            onVisibleChange(searchMode);
66
-          }
67
-        }
68
-      }}
69
-    >
70
-      <SearchOutlined
71
-        key="Icon"
72
-        style={{
73
-          cursor: 'pointer',
74
-        }}
75
-      />
76
-      <AutoComplete
77
-        key="AutoComplete"
78
-        className={inputClass}
79
-        value={value}
80
-        options={restProps.options}
81
-        onChange={(completeValue) => setValue(completeValue)}
82
-      >
83
-        <Input
84
-          size="small"
85
-          ref={inputRef}
86
-          defaultValue={defaultValue}
87
-          aria-label={placeholder}
88
-          placeholder={placeholder}
89
-          onKeyDown={(e) => {
90
-            if (e.key === 'Enter') {
91
-              if (restProps.onSearch) {
92
-                restProps.onSearch(value);
93
-              }
94
-            }
95
-          }}
96
-          onBlur={() => {
97
-            setSearchMode(false);
98
-          }}
99
-        />
100
-      </AutoComplete>
101
-    </div>
102
-  );
103
-};
104
-
105
-export default HeaderSearch;

+ 0
- 25
src/components/HeaderSearch/index.less Zobrazit soubor

@@ -1,25 +0,0 @@
1
-@import (reference) '~antd/es/style/themes/index';
2
-
3
-.headerSearch {
4
-  display: inline-flex;
5
-  align-items: center;
6
-  .input {
7
-    width: 0;
8
-    min-width: 0;
9
-    overflow: hidden;
10
-    background: transparent;
11
-    border-radius: 0;
12
-    transition: width 0.3s, margin-left 0.3s;
13
-    :global(.ant-select-selection) {
14
-      background: transparent;
15
-    }
16
-    input {
17
-      box-shadow: none !important;
18
-    }
19
-
20
-    &.show {
21
-      width: 210px;
22
-      margin-left: 8px;
23
-    }
24
-  }
25
-}

+ 0
- 126
src/components/NoticeIcon/NoticeIcon.tsx Zobrazit soubor

@@ -1,126 +0,0 @@
1
-import { BellOutlined } from '@ant-design/icons';
2
-import { Badge, Spin, Tabs } from 'antd';
3
-import classNames from 'classnames';
4
-import useMergedState from 'rc-util/es/hooks/useMergedState';
5
-import React from 'react';
6
-import HeaderDropdown from '../HeaderDropdown';
7
-import styles from './index.less';
8
-import type { NoticeIconTabProps } from './NoticeList';
9
-import NoticeList from './NoticeList';
10
-
11
-const { TabPane } = Tabs;
12
-
13
-export type NoticeIconProps = {
14
-  count?: number;
15
-  bell?: React.ReactNode;
16
-  className?: string;
17
-  loading?: boolean;
18
-  onClear?: (tabName: string, tabKey: string) => void;
19
-  onItemClick?: (item: API.NoticeIconItem, tabProps: NoticeIconTabProps) => void;
20
-  onViewMore?: (tabProps: NoticeIconTabProps, e: MouseEvent) => void;
21
-  onTabChange?: (tabTile: string) => void;
22
-  style?: React.CSSProperties;
23
-  onPopupVisibleChange?: (visible: boolean) => void;
24
-  popupVisible?: boolean;
25
-  clearText?: string;
26
-  viewMoreText?: string;
27
-  clearClose?: boolean;
28
-  emptyImage?: string;
29
-  children?: React.ReactElement<NoticeIconTabProps>[];
30
-};
31
-
32
-const NoticeIcon: React.FC<NoticeIconProps> & {
33
-  Tab: typeof NoticeList;
34
-} = (props) => {
35
-  const getNotificationBox = (): React.ReactNode => {
36
-    const {
37
-      children,
38
-      loading,
39
-      onClear,
40
-      onTabChange,
41
-      onItemClick,
42
-      onViewMore,
43
-      clearText,
44
-      viewMoreText,
45
-    } = props;
46
-    if (!children) {
47
-      return null;
48
-    }
49
-    const panes: React.ReactNode[] = [];
50
-    React.Children.forEach(children, (child: React.ReactElement<NoticeIconTabProps>): void => {
51
-      if (!child) {
52
-        return;
53
-      }
54
-      const { list, title, count, tabKey, showClear, showViewMore } = child.props;
55
-      const len = list && list.length ? list.length : 0;
56
-      const msgCount = count || count === 0 ? count : len;
57
-      const tabTitle: string = msgCount > 0 ? `${title} (${msgCount})` : title;
58
-      panes.push(
59
-        <TabPane tab={tabTitle} key={tabKey}>
60
-          <NoticeList
61
-            clearText={clearText}
62
-            viewMoreText={viewMoreText}
63
-            list={list}
64
-            tabKey={tabKey}
65
-            onClear={(): void => onClear && onClear(title, tabKey)}
66
-            onClick={(item): void => onItemClick && onItemClick(item, child.props)}
67
-            onViewMore={(event): void => onViewMore && onViewMore(child.props, event)}
68
-            showClear={showClear}
69
-            showViewMore={showViewMore}
70
-            title={title}
71
-          />
72
-        </TabPane>,
73
-      );
74
-    });
75
-    return (
76
-      <>
77
-        <Spin spinning={loading} delay={300}>
78
-          <Tabs className={styles.tabs} onChange={onTabChange}>
79
-            {panes}
80
-          </Tabs>
81
-        </Spin>
82
-      </>
83
-    );
84
-  };
85
-
86
-  const { className, count, bell } = props;
87
-
88
-  const [visible, setVisible] = useMergedState<boolean>(false, {
89
-    value: props.popupVisible,
90
-    onChange: props.onPopupVisibleChange,
91
-  });
92
-  const noticeButtonClass = classNames(className, styles.noticeButton);
93
-  const notificationBox = getNotificationBox();
94
-  const NoticeBellIcon = bell || <BellOutlined className={styles.icon} />;
95
-  const trigger = (
96
-    <span className={classNames(noticeButtonClass, { opened: visible })}>
97
-      <Badge count={count} style={{ boxShadow: 'none' }} className={styles.badge}>
98
-        {NoticeBellIcon}
99
-      </Badge>
100
-    </span>
101
-  );
102
-  if (!notificationBox) {
103
-    return trigger;
104
-  }
105
-
106
-  return (
107
-    <HeaderDropdown
108
-      placement="bottomRight"
109
-      overlay={notificationBox}
110
-      overlayClassName={styles.popover}
111
-      trigger={['click']}
112
-      visible={visible}
113
-      onVisibleChange={setVisible}
114
-    >
115
-      {trigger}
116
-    </HeaderDropdown>
117
-  );
118
-};
119
-
120
-NoticeIcon.defaultProps = {
121
-  emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
122
-};
123
-
124
-NoticeIcon.Tab = NoticeList;
125
-
126
-export default NoticeIcon;

+ 0
- 103
src/components/NoticeIcon/NoticeList.less Zobrazit soubor

@@ -1,103 +0,0 @@
1
-@import (reference) '~antd/es/style/themes/index';
2
-
3
-.list {
4
-  max-height: 400px;
5
-  overflow: auto;
6
-  &::-webkit-scrollbar {
7
-    display: none;
8
-  }
9
-  .item {
10
-    padding-right: 24px;
11
-    padding-left: 24px;
12
-    overflow: hidden;
13
-    cursor: pointer;
14
-    transition: all 0.3s;
15
-
16
-    .meta {
17
-      width: 100%;
18
-    }
19
-
20
-    .avatar {
21
-      margin-top: 4px;
22
-      background: @component-background;
23
-    }
24
-    .iconElement {
25
-      font-size: 32px;
26
-    }
27
-
28
-    &.read {
29
-      opacity: 0.4;
30
-    }
31
-    &:last-child {
32
-      border-bottom: 0;
33
-    }
34
-    &:hover {
35
-      background: @primary-1;
36
-    }
37
-    .title {
38
-      margin-bottom: 8px;
39
-      font-weight: normal;
40
-    }
41
-    .description {
42
-      font-size: 12px;
43
-      line-height: @line-height-base;
44
-    }
45
-    .datetime {
46
-      margin-top: 4px;
47
-      font-size: 12px;
48
-      line-height: @line-height-base;
49
-    }
50
-    .extra {
51
-      float: right;
52
-      margin-top: -1.5px;
53
-      margin-right: 0;
54
-      color: @text-color-secondary;
55
-      font-weight: normal;
56
-    }
57
-  }
58
-  .loadMore {
59
-    padding: 8px 0;
60
-    color: @primary-6;
61
-    text-align: center;
62
-    cursor: pointer;
63
-    &.loadedAll {
64
-      color: rgba(0, 0, 0, 0.25);
65
-      cursor: unset;
66
-    }
67
-  }
68
-}
69
-
70
-.notFound {
71
-  padding: 73px 0 88px;
72
-  color: @text-color-secondary;
73
-  text-align: center;
74
-  img {
75
-    display: inline-block;
76
-    height: 76px;
77
-    margin-bottom: 16px;
78
-  }
79
-}
80
-
81
-.bottomBar {
82
-  height: 46px;
83
-  color: @text-color;
84
-  line-height: 46px;
85
-  text-align: center;
86
-  border-top: 1px solid @border-color-split;
87
-  border-radius: 0 0 @border-radius-base @border-radius-base;
88
-  transition: all 0.3s;
89
-  div {
90
-    display: inline-block;
91
-    width: 50%;
92
-    cursor: pointer;
93
-    transition: all 0.3s;
94
-    user-select: none;
95
-
96
-    &:only-child {
97
-      width: 100%;
98
-    }
99
-    &:not(:only-child):last-child {
100
-      border-left: 1px solid @border-color-split;
101
-    }
102
-  }
103
-}

+ 0
- 112
src/components/NoticeIcon/NoticeList.tsx Zobrazit soubor

@@ -1,112 +0,0 @@
1
-import { Avatar, List } from 'antd';
2
-import classNames from 'classnames';
3
-import React from 'react';
4
-import styles from './NoticeList.less';
5
-
6
-export type NoticeIconTabProps = {
7
-  count?: number;
8
-  showClear?: boolean;
9
-  showViewMore?: boolean;
10
-  style?: React.CSSProperties;
11
-  title: string;
12
-  tabKey: API.NoticeIconItemType;
13
-  onClick?: (item: API.NoticeIconItem) => void;
14
-  onClear?: () => void;
15
-  emptyText?: string;
16
-  clearText?: string;
17
-  viewMoreText?: string;
18
-  list: API.NoticeIconItem[];
19
-  onViewMore?: (e: any) => void;
20
-};
21
-const NoticeList: React.FC<NoticeIconTabProps> = ({
22
-  list = [],
23
-  onClick,
24
-  onClear,
25
-  title,
26
-  onViewMore,
27
-  emptyText,
28
-  showClear = true,
29
-  clearText,
30
-  viewMoreText,
31
-  showViewMore = false,
32
-}) => {
33
-  if (!list || list.length === 0) {
34
-    return (
35
-      <div className={styles.notFound}>
36
-        <img
37
-          src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
38
-          alt="not found"
39
-        />
40
-        <div>{emptyText}</div>
41
-      </div>
42
-    );
43
-  }
44
-  return (
45
-    <div>
46
-      <List<API.NoticeIconItem>
47
-        className={styles.list}
48
-        dataSource={list}
49
-        renderItem={(item, i) => {
50
-          const itemCls = classNames(styles.item, {
51
-            [styles.read]: item.read,
52
-          });
53
-          // eslint-disable-next-line no-nested-ternary
54
-          const leftIcon = item.avatar ? (
55
-            typeof item.avatar === 'string' ? (
56
-              <Avatar className={styles.avatar} src={item.avatar} />
57
-            ) : (
58
-              <span className={styles.iconElement}>{item.avatar}</span>
59
-            )
60
-          ) : null;
61
-
62
-          return (
63
-            <div
64
-              onClick={() => {
65
-                onClick?.(item);
66
-              }}
67
-            >
68
-              <List.Item className={itemCls} key={item.key || i}>
69
-                <List.Item.Meta
70
-                  className={styles.meta}
71
-                  avatar={leftIcon}
72
-                  title={
73
-                    <div className={styles.title}>
74
-                      {item.title}
75
-                      <div className={styles.extra}>{item.extra}</div>
76
-                    </div>
77
-                  }
78
-                  description={
79
-                    <div>
80
-                      <div className={styles.description}>{item.description}</div>
81
-                      <div className={styles.datetime}>{item.datetime}</div>
82
-                    </div>
83
-                  }
84
-                />
85
-              </List.Item>
86
-            </div>
87
-          );
88
-        }}
89
-      />
90
-      <div className={styles.bottomBar}>
91
-        {showClear ? (
92
-          <div onClick={onClear}>
93
-            {clearText} {title}
94
-          </div>
95
-        ) : null}
96
-        {showViewMore ? (
97
-          <div
98
-            onClick={(e) => {
99
-              if (onViewMore) {
100
-                onViewMore(e);
101
-              }
102
-            }}
103
-          >
104
-            {viewMoreText}
105
-          </div>
106
-        ) : null}
107
-      </div>
108
-    </div>
109
-  );
110
-};
111
-
112
-export default NoticeList;

+ 0
- 152
src/components/NoticeIcon/index.jsx Zobrazit soubor

@@ -1,152 +0,0 @@
1
-import { getNotices } from '@/services/ant-design-pro/api';
2
-import { useModel, useRequest } from '@umijs/max';
3
-import { message, Tag } from 'antd';
4
-import { groupBy } from 'lodash';
5
-import moment from 'moment';
6
-import { useEffect, useState } from 'react';
7
-import styles from './index.less';
8
-import NoticeIcon from './NoticeIcon';
9
-
10
-// export type GlobalHeaderRightProps = {
11
-//   fetchingNotices?: boolean;
12
-//   onNoticeVisibleChange?: (visible: boolean) => void;
13
-//   onNoticeClear?: (tabName?: string) => void;
14
-// };
15
-
16
-const getNoticeData = (notices) => {
17
-  if (!notices || notices.length === 0 || !Array.isArray(notices)) {
18
-    return {};
19
-  }
20
-
21
-  const newNotices = notices.map((notice) => {
22
-    const newNotice = { ...notice };
23
-
24
-    if (newNotice.datetime) {
25
-      newNotice.datetime = moment(notice.datetime).fromNow();
26
-    }
27
-
28
-    if (newNotice.id) {
29
-      newNotice.key = newNotice.id;
30
-    }
31
-
32
-    if (newNotice.extra && newNotice.status) {
33
-      const color = {
34
-        todo: '',
35
-        processing: 'blue',
36
-        urgent: 'red',
37
-        doing: 'gold',
38
-      }[newNotice.status];
39
-      newNotice.extra = (
40
-        <Tag
41
-          color={color}
42
-          style={{
43
-            marginRight: 0,
44
-          }}
45
-        >
46
-          {newNotice.extra}
47
-        </Tag>
48
-      );
49
-    }
50
-
51
-    return newNotice;
52
-  });
53
-  return groupBy(newNotices, 'type');
54
-};
55
-
56
-const getUnreadData = (noticeData) => {
57
-  const unreadMsg = {};
58
-  Object.keys(noticeData).forEach((key) => {
59
-    const value = noticeData[key];
60
-
61
-    if (!unreadMsg[key]) {
62
-      unreadMsg[key] = 0;
63
-    }
64
-
65
-    if (Array.isArray(value)) {
66
-      unreadMsg[key] = value.filter((item) => !item.read).length;
67
-    }
68
-  });
69
-  return unreadMsg;
70
-};
71
-
72
-const NoticeIconView = () => {
73
-  const { initialState } = useModel('@@initialState');
74
-  const { currentUser } = initialState || {};
75
-  const [notices, setNotices] = useState([]);
76
-  const { data } = useRequest(getNotices);
77
-
78
-  useEffect(() => {
79
-    setNotices(data || []);
80
-  }, [data]);
81
-
82
-  const noticeData = getNoticeData(notices);
83
-  const unreadMsg = getUnreadData(noticeData || {});
84
-
85
-  const changeReadState = (id) => {
86
-    setNotices(
87
-      notices.map((item) => {
88
-        const notice = { ...item };
89
-        if (notice.id === id) {
90
-          notice.read = true;
91
-        }
92
-        return notice;
93
-      }),
94
-    );
95
-  };
96
-
97
-  const clearReadState = (title, key) => {
98
-    setNotices(
99
-      notices.map((item) => {
100
-        const notice = { ...item };
101
-        if (notice.type === key) {
102
-          notice.read = true;
103
-        }
104
-        return notice;
105
-      }),
106
-    );
107
-    message.success(`${'清空了'} ${title}`);
108
-  };
109
-
110
-  return (
111
-    <NoticeIcon
112
-      className={styles.action}
113
-      count={currentUser && currentUser.unreadCount}
114
-      onItemClick={(item) => {
115
-        changeReadState(item.id);
116
-      }}
117
-      onClear={(title, key) => clearReadState(title, key)}
118
-      loading={false}
119
-      clearText="清空"
120
-      viewMoreText="查看更多"
121
-      onViewMore={() => message.info('Click on view more')}
122
-      clearClose
123
-    >
124
-      <NoticeIcon.Tab
125
-        tabKey="notification"
126
-        count={unreadMsg.notification}
127
-        list={noticeData.notification}
128
-        title="通知"
129
-        emptyText="你已查看所有通知"
130
-        showViewMore
131
-      />
132
-      <NoticeIcon.Tab
133
-        tabKey="message"
134
-        count={unreadMsg.message}
135
-        list={noticeData.message}
136
-        title="消息"
137
-        emptyText="您已读完所有消息"
138
-        showViewMore
139
-      />
140
-      <NoticeIcon.Tab
141
-        tabKey="event"
142
-        title="待办"
143
-        emptyText="你已完成所有待办"
144
-        count={unreadMsg.event}
145
-        list={noticeData.event}
146
-        showViewMore
147
-      />
148
-    </NoticeIcon>
149
-  );
150
-};
151
-
152
-export default NoticeIconView;

+ 0
- 35
src/components/NoticeIcon/index.less Zobrazit soubor

@@ -1,35 +0,0 @@
1
-@import (reference) '~antd/es/style/themes/index';
2
-
3
-.popover {
4
-  position: relative;
5
-  width: 336px;
6
-}
7
-
8
-.noticeButton {
9
-  display: inline-block;
10
-  cursor: pointer;
11
-  transition: all 0.3s;
12
-}
13
-.icon {
14
-  padding: 4px;
15
-  vertical-align: middle;
16
-}
17
-
18
-.badge {
19
-  font-size: 16px;
20
-}
21
-
22
-.tabs {
23
-  :global {
24
-    .ant-tabs-nav-list {
25
-      margin: auto;
26
-    }
27
-
28
-    .ant-tabs-nav-scroll {
29
-      text-align: center;
30
-    }
31
-    .ant-tabs-nav {
32
-      margin-bottom: 0;
33
-    }
34
-  }
35
-}

+ 0
- 112
src/components/RightContent/AvatarDropdown.jsx Zobrazit soubor

@@ -1,112 +0,0 @@
1
-import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
2
-import { history, useModel } from '@umijs/max';
3
-import { Avatar, Menu, Spin } from 'antd';
4
-import { stringify } from 'querystring';
5
-import { useCallback } from 'react';
6
-import HeaderDropdown from '../HeaderDropdown';
7
-import styles from './index.less';
8
-
9
-/**
10
- * 退出登录,并且将当前的 url 保存
11
- */
12
-const loginOut = async () => {
13
-  // await outLogin();
14
-  sessionStorage.removeItem('token');
15
-  const { search, pathname } = history.location;
16
-  const urlParams = new URL(window.location.href).searchParams;
17
-  /** 此方法会跳转到 redirect 参数所在的位置 */
18
-  const redirect = urlParams.get('redirect');
19
-  // Note: There may be security issues, please note
20
-  if (window.location.pathname !== '/user/login' && !redirect) {
21
-    history.replace({
22
-      pathname: '/user/login',
23
-      search: stringify({
24
-        redirect: pathname + search,
25
-      }),
26
-    });
27
-  }
28
-};
29
-
30
-const AvatarDropdown = ({ menu }) => {
31
-  const { initialState, setInitialState } = useModel('@@initialState');
32
-
33
-  const onMenuClick = useCallback(
34
-    (event) => {
35
-      const { key } = event;
36
-      if (key === 'logout') {
37
-        setInitialState((s) => ({ ...s, currentUser: undefined }));
38
-        loginOut();
39
-        return;
40
-      }
41
-      history.push(`/account/${key}`);
42
-    },
43
-    [setInitialState],
44
-  );
45
-
46
-  const loading = (
47
-    <span className={`${styles.action} ${styles.account}`}>
48
-      <Spin
49
-        size="small"
50
-        style={{
51
-          marginLeft: 8,
52
-          marginRight: 8,
53
-        }}
54
-      />
55
-    </span>
56
-  );
57
-
58
-  if (!initialState) {
59
-    return loading;
60
-  }
61
-
62
-  const { currentUser } = initialState;
63
-
64
-  if (!currentUser || !currentUser.name) {
65
-    return loading;
66
-  }
67
-
68
-  const menuItems = [
69
-    ...(menu
70
-      ? [
71
-          {
72
-            key: 'center',
73
-            icon: <UserOutlined />,
74
-            label: '个人中心',
75
-          },
76
-          {
77
-            key: 'settings',
78
-            icon: <SettingOutlined />,
79
-            label: '个人设置',
80
-          },
81
-          {
82
-            type: 'divider',
83
-          },
84
-        ]
85
-      : []),
86
-    {
87
-      key: 'logout',
88
-      icon: <LogoutOutlined />,
89
-      label: '退出登录',
90
-    },
91
-  ];
92
-
93
-  const menuHeaderDropdown = (
94
-    <Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick} items={menuItems} />
95
-  );
96
-
97
-  return (
98
-    <HeaderDropdown overlay={menuHeaderDropdown}>
99
-      <span className={`${styles.action} ${styles.account}`}>
100
-        <Avatar
101
-          className={styles.avatar}
102
-          icon={<UserOutlined />}
103
-          // src={currentUser.avatar}
104
-          alt="avatar"
105
-        />
106
-        <span className={`${styles.name} anticon`}>{currentUser.name}</span>
107
-      </span>
108
-    </HeaderDropdown>
109
-  );
110
-};
111
-
112
-export default AvatarDropdown;

+ 0
- 27
src/components/RightContent/index.jsx Zobrazit soubor

@@ -1,27 +0,0 @@
1
-import { useModel } from '@umijs/max';
2
-import { Space } from 'antd';
3
-import Avatar from './AvatarDropdown';
4
-import styles from './index.less';
5
-
6
-// export type SiderTheme = 'light' | 'dark';
7
-
8
-const GlobalHeaderRight = () => {
9
-  const { initialState } = useModel('@@initialState');
10
-
11
-  if (!initialState || !initialState.settings) {
12
-    return null;
13
-  }
14
-
15
-  const { navTheme, layout } = initialState.settings;
16
-  let className = styles.right;
17
-
18
-  if ((navTheme === 'dark' && layout === 'top') || layout === 'mix') {
19
-    className = `${styles.right}  ${styles.dark}`;
20
-  }
21
-  return (
22
-    <Space className={className}>
23
-      <Avatar />
24
-    </Space>
25
-  );
26
-};
27
-export default GlobalHeaderRight;

+ 0
- 75
src/components/RightContent/index.less Zobrazit soubor

@@ -1,75 +0,0 @@
1
-@import (reference) '~antd/es/style/themes/index';
2
-
3
-@pro-header-hover-bg: rgba(255, 255, 255, 0.025);
4
-
5
-.menu {
6
-  :global(.anticon) {
7
-    margin-right: 8px;
8
-  }
9
-  :global(.ant-dropdown-menu-item) {
10
-    min-width: 160px;
11
-  }
12
-}
13
-
14
-.right {
15
-  display: flex;
16
-  float: right;
17
-  height: 48px;
18
-  margin-left: auto;
19
-  overflow: hidden;
20
-  .action {
21
-    display: flex;
22
-    align-items: center;
23
-    height: 48px;
24
-    padding: 0 12px;
25
-    cursor: pointer;
26
-    transition: all 0.3s;
27
-    > span {
28
-      vertical-align: middle;
29
-    }
30
-    &:hover {
31
-      background: @pro-header-hover-bg;
32
-    }
33
-    &:global(.opened) {
34
-      background: @pro-header-hover-bg;
35
-    }
36
-  }
37
-  .search {
38
-    padding: 0 12px;
39
-    &:hover {
40
-      background: transparent;
41
-    }
42
-  }
43
-  .account {
44
-    color: #fff;
45
-
46
-    .avatar {
47
-      margin-right: 8px;
48
-      color: @primary-color;
49
-      vertical-align: top;
50
-      // background: rgba(255, 255, 255, 0.85);
51
-    }
52
-  }
53
-}
54
-
55
-@media only screen and (max-width: @screen-md) {
56
-  :global(.ant-divider-vertical) {
57
-    vertical-align: unset;
58
-  }
59
-  .name {
60
-    display: none;
61
-  }
62
-  .right {
63
-    position: absolute;
64
-    top: 0;
65
-    right: 12px;
66
-    .account {
67
-      .avatar {
68
-        margin-right: 0;
69
-      }
70
-    }
71
-    .search {
72
-      display: none;
73
-    }
74
-  }
75
-}

+ 1
- 1
src/components/UploadFile/index.jsx Zobrazit soubor

@@ -1,7 +1,7 @@
1 1
 import React, { useCallback, useState } from 'react'
2 2
 import { UploadOutlined } from '@ant-design/icons';
3 3
 import { Upload, Button } from 'antd';
4
-import { uploadFile } from '@/services/api/rotationChart';
4
+import { uploadFile } from '@/services/rotationChart';
5 5
 
6 6
 const customRequest = ({ file, onError, onSuccess }) => {
7 7
   const data = new FormData();

+ 1
- 1
src/components/UploadVideo/index.jsx Zobrazit soubor

@@ -37,7 +37,7 @@ export default (props) => {
37 37
     <div>
38 38
       <Upload
39 39
       accept='video/*'
40
-        action={'/api/video/upload'}
40
+        action={'/video/upload'}
41 41
         className="image-uploader"
42 42
         showUploadList={false}
43 43
         // beforeUpload={beforeUpload}

+ 81
- 0
src/components/chart/index.jsx Zobrazit soubor

@@ -0,0 +1,81 @@
1
+import React, { useRef, useEffect } from 'react';
2
+
3
+// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
4
+import * as echarts from 'echarts/core';
5
+// 引入图表,图表后缀都为 Chart
6
+import {
7
+  BarChart,
8
+  PieChart,
9
+  LineChart,
10
+  GaugeChart,
11
+  RadarChart,
12
+  PictorialBarChart,
13
+} from 'echarts/charts';
14
+// 引入提示框,标题,直角坐标系,数据集,内置数据转换器组件,组件后缀都为 Component
15
+import {
16
+  TitleComponent,
17
+  TooltipComponent,
18
+  ToolboxComponent,
19
+  GridComponent,
20
+  DatasetComponent,
21
+  LegendComponent,
22
+  DataZoomComponent,
23
+  TransformComponent,
24
+  VisualMapComponent,
25
+} from 'echarts/components';
26
+// 标签自动布局,全局过渡动画等特性
27
+import { LabelLayout, UniversalTransition } from 'echarts/features';
28
+// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
29
+import { CanvasRenderer } from 'echarts/renderers';
30
+
31
+// 注册必须的组件
32
+echarts.use([
33
+  TitleComponent,
34
+  TooltipComponent,
35
+  ToolboxComponent,
36
+  GridComponent,
37
+  DatasetComponent,
38
+  LegendComponent,
39
+  DataZoomComponent,
40
+  TransformComponent,
41
+  VisualMapComponent,
42
+  BarChart,
43
+  PieChart,
44
+  LineChart,
45
+  GaugeChart,
46
+  RadarChart,
47
+  PictorialBarChart,
48
+  LabelLayout,
49
+  UniversalTransition,
50
+  CanvasRenderer
51
+]);
52
+
53
+export default (props) => {
54
+  const { className, style, option } = props;
55
+
56
+  const domRef = useRef();
57
+  const chartRef = useRef();
58
+
59
+  useEffect(() => {
60
+    if (!chartRef.current) {
61
+      chartRef.current = echarts.init(domRef.current);
62
+    }
63
+
64
+    const resize = () => {
65
+      const t = setTimeout(() => {
66
+        clearTimeout(t);
67
+        chartRef.current.resize();
68
+      }, 100);
69
+    };
70
+
71
+    chartRef.current.setOption(option);
72
+    resize();
73
+
74
+    window.addEventListener('resize', resize);    
75
+    return () => window.removeEventListener('resize', resize);
76
+  }, [option]);
77
+
78
+  return (
79
+    <div className={className} style={style} ref={domRef}></div>
80
+  )
81
+}

+ 0
- 267
src/components/index.md Zobrazit soubor

@@ -1,267 +0,0 @@
1
----
2
-title: 业务组件
3
-sidemenu: false
4
----
5
-
6
-> 此功能由[dumi](https://d.umijs.org/zh-CN/guide/advanced#umi-%E9%A1%B9%E7%9B%AE%E9%9B%86%E6%88%90%E6%A8%A1%E5%BC%8F)提供,dumi 是一个 📖 为组件开发场景而生的文档工具,用过的都说好。
7
-
8
-# 业务组件
9
-
10
-这里列举了 Pro 中所有用到的组件,这些组件不适合作为组件库,但是在业务中却真实需要。所以我们准备了这个文档,来指导大家是否需要使用这个组件。
11
-
12
-## Footer 页脚组件
13
-
14
-这个组件自带了一些 Pro 的配置,你一般都需要改掉它的信息。
15
-
16
-```tsx
17
-/**
18
- * background: '#f0f2f5'
19
- */
20
-import Footer from '@/components/Footer';
21
-
22
-export default () => <Footer />;
23
-```
24
-
25
-## HeaderDropdown 头部下拉列表
26
-
27
-HeaderDropdown 是 antd Dropdown 的封装,但是增加了移动端的特殊处理,用法也是相同的。
28
-
29
-```tsx
30
-/**
31
- * background: '#f0f2f5'
32
- */
33
-import HeaderDropdown from '@/components/HeaderDropdown';
34
-import { Button, Menu } from 'antd';
35
-
36
-export default () => {
37
-  const menuHeaderDropdown = (
38
-    <Menu selectedKeys={[]}>
39
-      <Menu.Item key="center">个人中心</Menu.Item>
40
-      <Menu.Item key="settings">个人设置</Menu.Item>
41
-      <Menu.Divider />
42
-      <Menu.Item key="logout">退出登录</Menu.Item>
43
-    </Menu>
44
-  );
45
-  return (
46
-    <HeaderDropdown overlay={menuHeaderDropdown}>
47
-      <Button>hover 展示菜单</Button>
48
-    </HeaderDropdown>
49
-  );
50
-};
51
-```
52
-
53
-## HeaderSearch 头部搜索框
54
-
55
-一个带补全数据的输入框,支持收起和展开 Input
56
-
57
-```tsx
58
-/**
59
- * background: '#f0f2f5'
60
- */
61
-import HeaderSearch from '@/components/HeaderSearch';
62
-
63
-export default () => {
64
-  return (
65
-    <HeaderSearch
66
-      placeholder="站内搜索"
67
-      defaultValue="umi ui"
68
-      options={[
69
-        { label: 'Ant Design Pro', value: 'Ant Design Pro' },
70
-        {
71
-          label: 'Ant Design',
72
-          value: 'Ant Design',
73
-        },
74
-        {
75
-          label: 'Pro Table',
76
-          value: 'Pro Table',
77
-        },
78
-        {
79
-          label: 'Pro Layout',
80
-          value: 'Pro Layout',
81
-        },
82
-      ]}
83
-      onSearch={(value) => {
84
-        console.log('input', value);
85
-      }}
86
-    />
87
-  );
88
-};
89
-```
90
-
91
-### API
92
-
93
-| 参数            | 说明                               | 类型                         | 默认值 |
94
-| --------------- | ---------------------------------- | ---------------------------- | ------ |
95
-| value           | 输入框的值                         | `string`                     | -      |
96
-| onChange        | 值修改后触发                       | `(value?: string) => void`   | -      |
97
-| onSearch        | 查询后触发                         | `(value?: string) => void`   | -      |
98
-| options         | 选项菜单的的列表                   | `{label,value}[]`            | -      |
99
-| defaultVisible  | 输入框默认是否显示,只有第一次生效 | `boolean`                    | -      |
100
-| visible         | 输入框是否显示                     | `boolean`                    | -      |
101
-| onVisibleChange | 输入框显示隐藏的回调函数           | `(visible: boolean) => void` | -      |
102
-
103
-## NoticeIcon 通知工具
104
-
105
-通知工具提供一个展示多种通知信息的界面。
106
-
107
-```tsx
108
-/**
109
- * background: '#f0f2f5'
110
- */
111
-import NoticeIcon from '@/components/NoticeIcon/NoticeIcon';
112
-import { message } from 'antd';
113
-
114
-export default () => {
115
-  const list = [
116
-    {
117
-      id: '000000001',
118
-      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
119
-      title: '你收到了 14 份新周报',
120
-      datetime: '2017-08-09',
121
-      type: 'notification',
122
-    },
123
-    {
124
-      id: '000000002',
125
-      avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
126
-      title: '你推荐的 曲妮妮 已通过第三轮面试',
127
-      datetime: '2017-08-08',
128
-      type: 'notification',
129
-    },
130
-  ];
131
-  return (
132
-    <NoticeIcon
133
-      count={10}
134
-      onItemClick={(item) => {
135
-        message.info(`${item.title} 被点击了`);
136
-      }}
137
-      onClear={(title: string, key: string) => message.info('点击了清空更多')}
138
-      loading={false}
139
-      clearText="清空"
140
-      viewMoreText="查看更多"
141
-      onViewMore={() => message.info('点击了查看更多')}
142
-      clearClose
143
-    >
144
-      <NoticeIcon.Tab
145
-        tabKey="notification"
146
-        count={2}
147
-        list={list}
148
-        title="通知"
149
-        emptyText="你已查看所有通知"
150
-        showViewMore
151
-      />
152
-      <NoticeIcon.Tab
153
-        tabKey="message"
154
-        count={2}
155
-        list={list}
156
-        title="消息"
157
-        emptyText="您已读完所有消息"
158
-        showViewMore
159
-      />
160
-      <NoticeIcon.Tab
161
-        tabKey="event"
162
-        title="待办"
163
-        emptyText="你已完成所有待办"
164
-        count={2}
165
-        list={list}
166
-        showViewMore
167
-      />
168
-    </NoticeIcon>
169
-  );
170
-};
171
-```
172
-
173
-### NoticeIcon API
174
-
175
-| 参数 | 说明 | 类型 | 默认值 |
176
-| --- | --- | --- | --- |
177
-| count | 有多少未读通知 | `number` | - |
178
-| bell | 铃铛的图表 | `ReactNode` | - |
179
-| onClear | 点击清空数据按钮 | `(tabName: string, tabKey: string) => void` | - |
180
-| onItemClick | 未读消息列被点击 | `(item: API.NoticeIconData, tabProps: NoticeIconTabProps) => void` | - |
181
-| onViewMore | 查看更多的按钮点击 | `(tabProps: NoticeIconTabProps, e: MouseEvent) => void` | - |
182
-| onTabChange | 通知 Tab 的切换 | `(tabTile: string) => void;` | - |
183
-| popupVisible | 通知显示是否展示 | `boolean` | - |
184
-| onPopupVisibleChange | 通知信息显示隐藏的回调函数 | `(visible: boolean) => void` | - |
185
-| clearText | 清空按钮的文字 | `string` | - |
186
-| viewMoreText | 查看更多的按钮文字 | `string` | - |
187
-| clearClose | 展示清空按钮 | `boolean` | - |
188
-| emptyImage | 列表为空时的兜底展示 | `ReactNode` | - |
189
-
190
-### NoticeIcon.Tab API
191
-
192
-| 参数         | 说明               | 类型                                 | 默认值 |
193
-| ------------ | ------------------ | ------------------------------------ | ------ |
194
-| count        | 有多少未读通知     | `number`                             | -      |
195
-| title        | 通知 Tab 的标题    | `ReactNode`                          | -      |
196
-| showClear    | 展示清除按钮       | `boolean`                            | `true` |
197
-| showViewMore | 展示加载更         | `boolean`                            | `true` |
198
-| tabKey       | Tab 的唯一 key     | `string`                             | -      |
199
-| onClick      | 子项的单击事件     | `(item: API.NoticeIconData) => void` | -      |
200
-| onClear      | 清楚按钮的点击     | `()=>void`                           | -      |
201
-| emptyText    | 为空的时候测试     | `()=>void`                           | -      |
202
-| viewMoreText | 查看更多的按钮文字 | `string`                             | -      |
203
-| onViewMore   | 查看更多的按钮点击 | `( e: MouseEvent) => void`           | -      |
204
-| list         | 通知信息的列表     | `API.NoticeIconData`                 | -      |
205
-
206
-### NoticeIconData
207
-
208
-```tsx | pure
209
-export interface NoticeIconData {
210
-  id: string;
211
-  key: string;
212
-  avatar: string;
213
-  title: string;
214
-  datetime: string;
215
-  type: string;
216
-  read?: boolean;
217
-  description: string;
218
-  clickClose?: boolean;
219
-  extra: any;
220
-  status: string;
221
-}
222
-```
223
-
224
-## RightContent
225
-
226
-RightContent 是以上几个组件的组合,同时新增了 plugins 的 `SelectLang` 插件。
227
-
228
-```tsx | pure
229
-<Space>
230
-  <HeaderSearch
231
-    placeholder="站内搜索"
232
-    defaultValue="umi ui"
233
-    options={[
234
-      { label: <a href="https://umijs.org/zh/guide/umi-ui.html">umi ui</a>, value: 'umi ui' },
235
-      {
236
-        label: <a href="next.ant.design">Ant Design</a>,
237
-        value: 'Ant Design',
238
-      },
239
-      {
240
-        label: <a href="https://protable.ant.design/">Pro Table</a>,
241
-        value: 'Pro Table',
242
-      },
243
-      {
244
-        label: <a href="https://prolayout.ant.design/">Pro Layout</a>,
245
-        value: 'Pro Layout',
246
-      },
247
-    ]}
248
-  />
249
-  <Tooltip title="使用文档">
250
-    <span
251
-      className={styles.action}
252
-      onClick={() => {
253
-        window.location.href = 'https://pro.ant.design/docs/getting-started';
254
-      }}
255
-    >
256
-      <QuestionCircleOutlined />
257
-    </span>
258
-  </Tooltip>
259
-  <Avatar />
260
-  {REACT_APP_ENV && (
261
-    <span>
262
-      <Tag color={ENVTagColor[REACT_APP_ENV]}>{REACT_APP_ENV}</Tag>
263
-    </span>
264
-  )}
265
-  <SelectLang className={styles.action} />
266
-</Space>
267
-```

+ 10
- 0
src/components/page/Container.jsx Zobrazit soubor

@@ -0,0 +1,10 @@
1
+import React from 'react';
2
+import './style.less'
3
+
4
+export default (props) => {
5
+  return (
6
+    <div className="page-container">
7
+      {props.children}
8
+    </div>
9
+  )
10
+}

+ 14
- 0
src/components/page/index.jsx Zobrazit soubor

@@ -0,0 +1,14 @@
1
+import React, { useEffect } from 'react';
2
+// import { PageHeader } from 'antd';
3
+import { useModel } from '@/store';
4
+import Container from './Container';
5
+
6
+export default (props) => {
7
+  // const { children, ...headerProps } = props;
8
+  
9
+  return (
10
+    <Container>
11
+      {props.children}
12
+    </Container>
13
+  )
14
+}

+ 5
- 0
src/components/page/style.less Zobrazit soubor

@@ -0,0 +1,5 @@
1
+
2
+.page-container {
3
+  margin: 24px;
4
+  margin-bottom: 0;
5
+}

+ 0
- 45
src/e2e/baseLayout.e2e.spec.ts Zobrazit soubor

@@ -1,45 +0,0 @@
1
-import type { Page } from '@playwright/test';
2
-import { expect, test } from '@playwright/test';
3
-const { uniq } = require('lodash');
4
-const RouterConfig = require('../../config/routes').default;
5
-
6
-const BASE_URL = `http://localhost:${process.env.PORT || 8001}`;
7
-
8
-function formatter(routes: any, parentPath = ''): string[] {
9
-  const fixedParentPath = parentPath.replace(/\/{1,}/g, '/');
10
-  let result: string[] = [];
11
-  routes.forEach((item: { path: string; routes: string }) => {
12
-    if (item.path && !item.path.startsWith('/')) {
13
-      result.push(`${fixedParentPath}/${item.path}`.replace(/\/{1,}/g, '/'));
14
-    }
15
-    if (item.path && item.path.startsWith('/')) {
16
-      result.push(`${item.path}`.replace(/\/{1,}/g, '/'));
17
-    }
18
-    if (item.routes) {
19
-      result = result.concat(
20
-        formatter(item.routes, item.path ? `${fixedParentPath}/${item.path}` : parentPath),
21
-      );
22
-    }
23
-  });
24
-  return uniq(result.filter((item) => !!item));
25
-}
26
-
27
-const testPage = (path: string, page: Page) => async () => {
28
-  await page.evaluate(() => {
29
-    localStorage.setItem('antd-pro-authority', '["admin"]');
30
-  });
31
-  await page.goto(`${BASE_URL}${path}`);
32
-  await page.waitForSelector('footer', {
33
-    timeout: 2000,
34
-  });
35
-  const haveFooter = await page.evaluate(() => document.getElementsByTagName('footer').length > 0);
36
-  expect(haveFooter).toBeTruthy();
37
-};
38
-
39
-const routers = formatter(RouterConfig);
40
-
41
-routers.forEach((route) => {
42
-  test(`test route page ${route}`, async ({ page }) => {
43
-    await testPage(route, page);
44
-  });
45
-});

+ 0
- 91
src/global.jsx Zobrazit soubor

@@ -1,91 +0,0 @@
1
-import { useIntl } from '@umijs/max';
2
-import { Button, message, notification } from 'antd';
3
-import defaultSettings from '../config/defaultSettings';
4
-
5
-const { pwa } = defaultSettings;
6
-const isHttps = document.location.protocol === 'https:';
7
-
8
-const clearCache = () => {
9
-  // remove all caches
10
-  if (window.caches) {
11
-    caches
12
-      .keys()
13
-      .then((keys) => {
14
-        keys.forEach((key) => {
15
-          caches.delete(key);
16
-        });
17
-      })
18
-      .catch((e) => console.log(e));
19
-  }
20
-};
21
-
22
-// if pwa is true
23
-if (pwa) {
24
-  // Notify user if offline now
25
-  window.addEventListener('sw.offline', () => {
26
-    message.warning(useIntl().formatMessage({ id: 'app.pwa.offline' }));
27
-  });
28
-
29
-  // Pop up a prompt on the page asking the user if they want to use the latest version
30
-  window.addEventListener('sw.updated', (event) => {
31
-    const e = event ;
32
-    const reloadSW = async () => {
33
-      // Check if there is sw whose state is waiting in ServiceWorkerRegistration
34
-      // https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration
35
-      const worker = e.detail && e.detail.waiting;
36
-      if (!worker) {
37
-        return true;
38
-      }
39
-      // Send skip-waiting event to waiting SW with MessageChannel
40
-      await new Promise((resolve, reject) => {
41
-        const channel = new MessageChannel();
42
-        channel.port1.onmessage = (msgEvent) => {
43
-          if (msgEvent.data.error) {
44
-            reject(msgEvent.data.error);
45
-          } else {
46
-            resolve(msgEvent.data);
47
-          }
48
-        };
49
-        worker.postMessage({ type: 'skip-waiting' }, [channel.port2]);
50
-      });
51
-
52
-      clearCache();
53
-      window.location.reload();
54
-      return true;
55
-    };
56
-    const key = `open${Date.now()}`;
57
-    const btn = (
58
-      <Button
59
-        type="primary"
60
-        onClick={() => {
61
-          notification.close(key);
62
-          reloadSW();
63
-        }}
64
-      >
65
-        {useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.ok' })}
66
-      </Button>
67
-    );
68
-    notification.open({
69
-      message: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated' }),
70
-      description: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }),
71
-      btn,
72
-      key,
73
-      onClose: async () => null,
74
-    });
75
-  });
76
-} else if ('serviceWorker' in navigator && isHttps) {
77
-  // unregister service worker
78
-  const { serviceWorker } = navigator;
79
-  if (serviceWorker.getRegistrations) {
80
-    serviceWorker.getRegistrations().then((sws) => {
81
-      sws.forEach((sw) => {
82
-        sw.unregister();
83
-      });
84
-    });
85
-  }
86
-  serviceWorker.getRegistration().then((sw) => {
87
-    if (sw) sw.unregister();
88
-  });
89
-
90
-  clearCache();
91
-}

+ 0
- 102
src/global.less Zobrazit soubor

@@ -1,102 +0,0 @@
1
-@import '~antd/es/style/variable.less';
2
-
3
-html,
4
-body,
5
-#root {
6
-  height: 100%;
7
-}
8
-
9
-.ant-pro-sider-actions {
10
-  display: none !important;
11
-}
12
-
13
-.colorWeak {
14
-  filter: invert(80%);
15
-}
16
-
17
-.ant-layout {
18
-  min-height: 100vh;
19
-}
20
-
21
-.ant-pro .ant-layout-header.ant-pro-layout-header {
22
-  padding: 0;
23
-}
24
-
25
-.ant-pro-top-nav-header-menu {
26
-  line-height: 64px !important;
27
-}
28
-
29
-.ant-pro-layout .ant-pro-top-nav-header-base-menu.ant-menu-light .ant-menu-item-selected {
30
-  border-radius: 0;
31
-}
32
-
33
-.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
34
-  left: unset;
35
-}
36
-
37
-canvas {
38
-  display: block;
39
-}
40
-
41
-body {
42
-  text-rendering: optimizeLegibility;
43
-  -webkit-font-smoothing: antialiased;
44
-  -moz-osx-font-smoothing: grayscale;
45
-}
46
-
47
-ul,
48
-ol {
49
-  list-style: none;
50
-}
51
-
52
-@media (max-width: @screen-xs) {
53
-  .ant-table {
54
-    width: 100%;
55
-    overflow-x: auto;
56
-    &-thead > tr,
57
-    &-tbody > tr {
58
-      > th,
59
-      > td {
60
-        white-space: pre;
61
-        > span {
62
-          display: block;
63
-        }
64
-      }
65
-    }
66
-  }
67
-}
68
-
69
-.ant-page-header {
70
-  background-color: #fff !important;
71
-  // box-shadow: 0 2px 2px rgba(0, 0, 0, 0.04);
72
-}
73
-
74
-// 兼容 360
75
-.ant-pro-sider-collapsed-button {
76
-  top: 18px;
77
-  right: -13px;
78
-}
79
-
80
-// .ant-pro .ant-pro-layout .ant-pro-sider-mix {
81
-//   top: 64px;
82
-// }
83
-
84
-.ant-layout-sider-children {
85
-  padding: 8px;
86
-}
87
-
88
-.ant-pro .ant-pro-layout .ant-pro-sider-logo {
89
-  padding: 16px;
90
-}
91
-
92
-.ant-pro-page-container .ant-pro-page-container-warp-page-header ~ .ant-pro-grid-content .ant-pro-page-container-children-content {
93
-  margin: 8px 40px 40px 40px;
94
-}
95
-
96
-.ant-pro-table-list-toolbar-container {
97
-  padding: 16px 0;
98
-}
99
-
100
-.ant-pro-card .ant-pro-card-body {
101
-  padding: 16px 24px;
102
-}

+ 77
- 0
src/index.less Zobrazit soubor

@@ -0,0 +1,77 @@
1
+html, body, #root {
2
+  width: 100%;
3
+  height: 100%;
4
+  margin: 0;
5
+}
6
+
7
+:root {
8
+  --theme-color: #081A48;
9
+  --theme-front: #fff;
10
+  --header-height: 94px;
11
+  --siderbar-width: 240px;
12
+}
13
+
14
+.main-layout {
15
+  height: 100vh;
16
+  display: flex;
17
+  flex-direction: column;
18
+}
19
+
20
+.fixd-header {
21
+  width: 100%;
22
+  position: fixed;
23
+  top: 0;
24
+  height: var(--header-height);
25
+  line-height: var(--header-height);
26
+  z-index: 100;
27
+}
28
+
29
+.ant-layout {
30
+  background-color: #f0f2f5;
31
+}
32
+
33
+.ant-layout-header {
34
+  line-height: var(--header-height);
35
+  box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
36
+  // border-bottom: 1px solid gainsboro;
37
+  z-index: 10;
38
+}
39
+
40
+.layout-sidebar {
41
+  width: var(--siderbar-width);
42
+  background-color: var(--theme-color);
43
+  color: var(--theme-front);
44
+  box-shadow: 1px 0 4px 0 rgba(0, 21, 41, 0.08);
45
+
46
+  .ant-menu {
47
+    font-size: 16px;
48
+    background: var(--theme-color);
49
+  }
50
+}
51
+
52
+
53
+// 兼容 360
54
+.ant-pro-sider-collapsed-button {
55
+  top: 18px;
56
+  right: -13px;
57
+}
58
+
59
+.ant-pro .ant-pro-layout .ant-pro-sider-logo {
60
+  padding: 16px;
61
+}
62
+
63
+.ant-pro .ant-pro-query-filter .ant-form-item {
64
+  margin: 0;
65
+}
66
+
67
+.ant-pro-page-container .ant-pro-page-container-warp-page-header ~ .ant-pro-grid-content .ant-pro-page-container-children-content {
68
+  margin: 8px 40px 40px 40px;
69
+}
70
+
71
+.ant-pro-table-list-toolbar-container {
72
+  padding: 16px 0;
73
+}
74
+
75
+.ant-pro-card .ant-pro-card-body {
76
+  padding: 16px 24px;
77
+}

+ 30
- 0
src/layouts/AuthLayout/components/Container.jsx Zobrazit soubor

@@ -0,0 +1,30 @@
1
+import React, { useEffect, useRef, useMemo, useState } from 'react';
2
+import { Layout, Spin } from 'antd';
3
+import { Outlet } from "react-router-dom";
4
+import PageTransition from './PageTransition';
5
+import Footer from './Footer';
6
+
7
+const { Content } = Layout;
8
+
9
+export default (props) => {  
10
+  const containerRef = useRef();
11
+  const [minHeight, setMinHeight] = useState(0);
12
+  const contentStyle = useMemo(() => ({ minHeight: `${minHeight}px` }), [minHeight]);
13
+  
14
+  useEffect(() => {
15
+    const containerHeight = containerRef.current.offsetHeight;
16
+    const footerHeight = document.querySelector('.ant-layout-footer').offsetHeight;
17
+    setMinHeight(containerHeight - footerHeight);
18
+  }, []);
19
+
20
+  return (
21
+    <div className='layout-container' ref={containerRef}>
22
+      <Content style={contentStyle}>
23
+        {/* <PageTransition location={props.location}> */}
24
+          <Outlet />
25
+        {/* </PageTransition> */}
26
+      </Content>
27
+      <Footer />
28
+    </div>
29
+  )
30
+}

+ 14
- 0
src/layouts/AuthLayout/components/Footer.jsx Zobrazit soubor

@@ -0,0 +1,14 @@
1
+import React from 'react';
2
+import { Layout, Spin } from 'antd';
3
+
4
+const { Footer } = Layout;
5
+
6
+const year = new Date().getFullYear();
7
+export default (props) => {
8
+
9
+  const copyRight = `南京云致 @${year}`
10
+
11
+  return (
12
+    <Footer style={{ textAlign: 'center' }}>{copyRight}</Footer>
13
+  )
14
+}

+ 28
- 0
src/layouts/AuthLayout/components/Header/Exit.jsx Zobrazit soubor

@@ -0,0 +1,28 @@
1
+import React from 'react';
2
+import { useNavigate } from 'react-router-dom';
3
+import { LogoutOutlined } from '@ant-design/icons';
4
+import { Button, Modal } from 'antd';
5
+import { useModel } from '@/store';
6
+
7
+const { confirm } = Modal;
8
+
9
+export default (props) => {
10
+  const navigate = useNavigate();
11
+  const { setUser } = useModel('user');
12
+
13
+  const onExit = () => {
14
+
15
+    confirm({
16
+      title: '确认退出系统?',
17
+      onOk: () => {
18
+        sessionStorage.removeItem('token');
19
+        setUser();
20
+        navigate('/login?back=true');
21
+      }
22
+    });
23
+  }
24
+
25
+  return (
26
+    <Button className='font' type="text" icon={<LogoutOutlined />} onClick={onExit}>退出</Button>
27
+  )
28
+}

+ 28
- 0
src/layouts/AuthLayout/components/Header/SplitMenu.jsx Zobrazit soubor

@@ -0,0 +1,28 @@
1
+import React from 'react';
2
+import { Menu } from 'antd';
3
+import { useNavigate } from 'react-router-dom';
4
+
5
+export default (props) => {
6
+  const { items, onChange, location } = props;
7
+
8
+  const navigate = useNavigate();
9
+  const [selectedKeys, setSelectedKeys] = React.useState([]);
10
+
11
+  const renderItems = React.useMemo(() => items.map(x => ({ ...x, children: undefined })), [items]);
12
+
13
+  const rootPath = React.useMemo(() => `/${location.pathname.split('/')[1]}`, [location.pathname]);
14
+
15
+  const onClick = (item) => {
16
+    onChange(item.key);
17
+    navigate(item.key);
18
+  };
19
+
20
+  React.useEffect(() => {
21
+    setSelectedKeys([rootPath]);
22
+    onChange(rootPath);
23
+  }, [rootPath]);
24
+
25
+  return (
26
+    <Menu className='split-menu' mode="horizontal" items={renderItems} selectedKeys={selectedKeys} onClick={onClick} />
27
+  )
28
+}

+ 26
- 0
src/layouts/AuthLayout/components/Header/Title.jsx Zobrazit soubor

@@ -0,0 +1,26 @@
1
+import { Typography } from 'antd';
2
+import useRoute from '@/utils/hooks/useRoute';
3
+
4
+const { Title } = Typography;
5
+
6
+const titleStyle = {
7
+  margin: 0,
8
+}
9
+
10
+const spanStyle = {
11
+  display: 'inline-block',
12
+  width: '24px',
13
+  textAlign: 'center'
14
+}
15
+
16
+export default (props) => {
17
+  const route = useRoute();
18
+  const { title } = route && route.meta || {}
19
+
20
+  return (
21
+    <Title level={5} style={titleStyle}>
22
+      { title && <span style={spanStyle}>&raquo;</span> }
23
+      { title && <span>{title}</span> }
24
+    </Title>
25
+  );
26
+}

+ 88
- 0
src/layouts/AuthLayout/components/Header/User.jsx Zobrazit soubor

@@ -0,0 +1,88 @@
1
+import React, { useState, forwardRef, useRef, useImperativeHandle } from 'react';
2
+import { Avatar, Button, Dropdown, Menu, Form, Input, Modal } from 'antd';
3
+import { useModel } from '@/store'
4
+
5
+const ChangePassword = forwardRef((props, ref) => {
6
+  const [visible, setVisible] = useState(false);
7
+
8
+  const onFinish = (values) => {
9
+    console.log('Success:', values);
10
+  };
11
+
12
+  useImperativeHandle(ref, () => {
13
+    return {
14
+      show: () => setVisible(true),
15
+    }
16
+  });
17
+
18
+  return (
19
+    <Modal title="修改密码" visible={visible} onCancel={() => setVisible(false)}>
20
+      <Form
21
+        labelCol={{ span: 8 }}
22
+        wrapperCol={{ span: 16 }}
23
+        onFinish={onFinish}
24
+        autoComplete="off"
25
+      >
26
+        <Form.Item
27
+          label="原始密码"
28
+          name="password"
29
+          rules={[{ required: true, message: '请输入原始密码!' }]}
30
+        >
31
+          <Input.Password />
32
+        </Form.Item>
33
+
34
+        <Form.Item
35
+          label="新密码"
36
+          name="newPassword"
37
+          rules={[{ required: true, message: '请输入新密码!' }]}
38
+        >
39
+          <Input.Password />
40
+        </Form.Item>
41
+
42
+        <Form.Item
43
+          label="确认新密码"
44
+          name="newPassword2"
45
+          rules={[{ required: true, message: '请输入新密码!' }]}
46
+        >
47
+          <Input.Password />
48
+        </Form.Item>
49
+
50
+        <Form.Item wrapperCol={{ offset: 8, span: 16 }}>
51
+          <Button type="primary" htmlType="submit">
52
+            提交
53
+          </Button>
54
+        </Form.Item>
55
+      </Form>
56
+    </Modal>
57
+  )
58
+});
59
+
60
+export default (props) => {
61
+  const menuItems = [
62
+    {
63
+      key: 'changePassword',
64
+      label: '修改密码',
65
+    }
66
+  ];
67
+
68
+  const passRef = useRef();
69
+  const { user = {} } = useModel('user');
70
+
71
+  const onClick = ({ key }) => {
72
+    if (key === 'changePassword') {
73
+      passRef.current.show();
74
+    }
75
+  };
76
+
77
+  const menu = <Menu items={menuItems} onClick={onClick} />;
78
+
79
+  return (
80
+    <Dropdown overlay={menu}>
81
+      <div className="user-info">
82
+        <Avatar size={24} src="https://joeschmoe.io/api/v1/random" />
83
+        <span className='font'>{user.name}</span>
84
+        <ChangePassword ref={passRef} />
85
+      </div>
86
+    </Dropdown>
87
+  )
88
+}

+ 30
- 0
src/layouts/AuthLayout/components/Header/index.jsx Zobrazit soubor

@@ -0,0 +1,30 @@
1
+import React, { useMemo } from 'react';
2
+import { Layout, Space } from 'antd';
3
+import classNames from 'classnames';
4
+import Logo from '../Logo';
5
+import Title from './Title';
6
+import User from './User';
7
+import Exit from './Exit';
8
+import SplitMenu from './SplitMenu';
9
+
10
+const { Header } = Layout;
11
+
12
+export default (props) => {
13
+  const { menus, theme, location, onMenuChange } = props;
14
+
15
+  const className = useMemo(() => classNames({
16
+    'layout-header': true,
17
+    'light': theme === 'light',
18
+  }), [theme]);
19
+
20
+  return (
21
+    <Header className={className}>
22
+      <Logo />
23
+      <SplitMenu items={menus} location={location} onChange={onMenuChange} />
24
+      <Space>
25
+        <User />
26
+        <Exit />
27
+      </Space>
28
+    </Header>
29
+  )
30
+}

+ 19
- 0
src/layouts/AuthLayout/components/HtmlTitle.jsx Zobrazit soubor

@@ -0,0 +1,19 @@
1
+
2
+import { Helmet } from "react-helmet";
3
+import { useModel } from '@/store';
4
+import useRoute from '@/utils/hooks/useRoute';
5
+
6
+export default (props) => {
7
+  const { app } = useModel('system');
8
+  const route = useRoute();
9
+  const { title } = route && route.meta || {}
10
+  
11
+  const titleTemplate = `%s - ${app.fullName}`;
12
+  const defaultTitle = app.fullName;
13
+
14
+  return (
15
+    <Helmet titleTemplate={titleTemplate} defaultTitle={defaultTitle}>
16
+      <title>{title}</title>
17
+    </Helmet>
18
+  );
19
+}

+ 17
- 0
src/layouts/AuthLayout/components/Logo.jsx Zobrazit soubor

@@ -0,0 +1,17 @@
1
+import React from 'react';
2
+import { Typography } from 'antd';
3
+import { NavLink } from "react-router-dom";
4
+import { useModel } from '@/store';
5
+
6
+const { Title } = Typography;
7
+
8
+export default (props) => {
9
+  const { app } = useModel('system');
10
+
11
+  return (
12
+    <NavLink className='logo'  to="/">
13
+      <img src="./logo.png" alt="" />
14
+      {/* <Title level={5}>{app.shorName}</Title> */}
15
+    </NavLink>
16
+  )
17
+}

+ 41
- 0
src/layouts/AuthLayout/components/Menus.jsx Zobrazit soubor

@@ -0,0 +1,41 @@
1
+import React, { useState } from 'react';
2
+import { useNavigate, useLocation } from "react-router-dom";
3
+import { Menu } from 'antd';
4
+
5
+const linkTo = url => {
6
+  const a = document.createElement('a');
7
+  a.href = item.key;
8
+  a.target = '_blank';
9
+  a.click();
10
+}
11
+
12
+const menuStyle = { height: '100%' };
13
+
14
+export default (props) => {
15
+  const { theme, items, location } = props;
16
+  // const [selectedKeys, setSelectedKeys] = useState([]);
17
+
18
+  const navigate = useNavigate();
19
+
20
+  const onClick = (item) => {
21
+    // console.log(item);
22
+
23
+    if (item.key.indexOf('http') === 0) {
24
+      // http 开头说明是外部链接
25
+      linkTo(item.key);
26
+    } else {
27
+      // setSelectedKeys([item.key]);
28
+      navigate(item.key);
29
+    }
30
+  }
31
+
32
+  // React.useEffect(() => {
33
+  //   if (location.pathname) {
34
+  //     setSelectedKeys([location.pathname]);
35
+  //   }
36
+  // }, [location.pathname]);
37
+
38
+  return (
39
+    <Menu style={menuStyle} theme={theme} items={items} onClick={onClick} selectedKeys={[location.pathname]} />
40
+  )
41
+}

+ 21
- 0
src/layouts/AuthLayout/components/PageTransition/index.jsx Zobrazit soubor

@@ -0,0 +1,21 @@
1
+import { TransitionGroup, CSSTransition } from 'react-transition-group';
2
+import './style.less';
3
+
4
+export default (props) => {
5
+  const { location } = props;
6
+  const currentURL = location.pathname + location.search;
7
+
8
+  return (
9
+    <TransitionGroup component={null}>
10
+      <CSSTransition
11
+        key={currentURL}
12
+        addEndListener={(node, done) => node.addEventListener("transitionend", done, false)}
13
+        classNames="page-fade"
14
+      >
15
+        <div>
16
+          {props.children}
17
+        </div>
18
+      </CSSTransition>
19
+    </TransitionGroup>
20
+  );
21
+}

+ 21
- 0
src/layouts/AuthLayout/components/PageTransition/style.less Zobrazit soubor

@@ -0,0 +1,21 @@
1
+
2
+.page-fade-enter {
3
+  opacity: 0;
4
+  transform: translateY(10%);
5
+}
6
+.page-fade-enter-active {
7
+  opacity: 1;
8
+  transform: translateY(0%);
9
+}
10
+.page-fade-exit {
11
+  opacity: 1;
12
+  transform: translateY(0%);
13
+}
14
+.page-fade-exit-active {
15
+  opacity: 0;
16
+  transform: translateY(10%);
17
+}
18
+.page-fade-enter-active,
19
+.page-fade-exit-active {
20
+  transition: opacity 220ms, transform 220ms;
21
+}

+ 13
- 0
src/layouts/AuthLayout/components/RequireLogin.jsx Zobrazit soubor

@@ -0,0 +1,13 @@
1
+import React, { useState } from 'react'
2
+import { useLocation, Navigate } from "react-router-dom"
3
+
4
+export default (props) => {
5
+  const { user } = props
6
+  const location = useLocation()
7
+
8
+  return props.children
9
+
10
+  // return !user || !user.isLoged ?
11
+  //   <Navigate to="/login" state={{ from: location }} replace /> :
12
+  //   props.children
13
+}

+ 20
- 0
src/layouts/AuthLayout/components/SiderBar.jsx Zobrazit soubor

@@ -0,0 +1,20 @@
1
+import React, { useMemo } from 'react';
2
+import { Layout, Spin } from 'antd';
3
+import { getPropertyValue } from '@/utils/css';
4
+import Menus from './Menus';
5
+
6
+const { Sider } = Layout;
7
+
8
+export default (props) => {
9
+  const { theme, location, menus } = props;
10
+
11
+  const width = useMemo(() => {
12
+    return /\d+/.exec(getPropertyValue('--siderbar-width'))[0] - 0;
13
+  }, []);
14
+
15
+  return (
16
+    <Sider className='layout-sidebar' theme={theme} collapsible width={width}>
17
+      <Menus theme={theme} items={menus} location={location} />
18
+    </Sider>
19
+  );
20
+}

+ 48
- 0
src/layouts/AuthLayout/index.jsx Zobrazit soubor

@@ -0,0 +1,48 @@
1
+import React, { useEffect, useRef, useMemo, useState } from 'react';
2
+import { Layout, Spin } from 'antd';
3
+import { useLocation } from "react-router-dom";
4
+import { useModel } from '@/store';
5
+import { getItems } from '@/routes/menus';
6
+import RequireLogin from './components/RequireLogin';
7
+import SiderBar from './components/SiderBar';
8
+import Header from './components/Header';
9
+import Container from './components/Container';
10
+import HtmlTitle from './components/HtmlTitle';
11
+import useReady from './useReady';
12
+
13
+import './style.less';
14
+
15
+export default (props) => {
16
+  const { theme } = useModel('system');
17
+  const { user, setUser } = useModel('user');
18
+
19
+  const allMenus = useMemo(() => getItems(), []);
20
+  const [siderMenus, setSiderMenus] = useState([]);
21
+
22
+  // 如果当前未登录, 跳转到登录页
23
+  useReady({ user, setUser });
24
+
25
+  const location = useLocation();
26
+
27
+  const onSplitMenuChange = (key) => {
28
+    const target = allMenus.filter(x => x.key === key)[0];
29
+    if (target) {
30
+      setSiderMenus(target.children || []);
31
+    }
32
+  }
33
+
34
+  return (
35
+    <Spin spinning={!user} size="large">
36
+      <HtmlTitle />
37
+      <RequireLogin>
38
+        <Layout style={{ minHeight: '100vh' }}>
39
+          <Header theme={theme} menus={allMenus} location={location} onMenuChange={onSplitMenuChange} />
40
+          <Layout>
41
+            <SiderBar theme={theme} menus={siderMenus} location={location} />
42
+            <Container location={location} />
43
+          </Layout>
44
+        </Layout>
45
+      </RequireLogin>
46
+    </Spin>
47
+  );
48
+}

+ 105
- 0
src/layouts/AuthLayout/style.less Zobrazit soubor

@@ -0,0 +1,105 @@
1
+.layout-header {
2
+  height: var(--header-height);
3
+  box-sizing: border-box;
4
+  padding: 0;
5
+  display: flex;
6
+  align-items: center;
7
+  justify-content: space-between;
8
+  color: #fff;
9
+  background: #0D267C;
10
+
11
+  .split-menu {
12
+    flex: 0;
13
+    max-width: 1000px;
14
+    background: transparent;
15
+    font-size: 20px;
16
+    color: #fff;
17
+    border-bottom-color: transparent;
18
+
19
+    .ant-menu-item-selected {
20
+      color: #fff;
21
+    }
22
+
23
+    .ant-menu-item .ant-menu-item-icon {
24
+      font-size: 20px;
25
+    }
26
+
27
+    .ant-menu-item-selected::after {
28
+      border-bottom-width: 6px !important;
29
+    }
30
+  }
31
+
32
+  &.light {
33
+    background-color: #fff;
34
+    color: #000;
35
+  }
36
+
37
+  .header-content {
38
+    flex: 1;
39
+  }
40
+
41
+  .font {
42
+    color: inherit;
43
+    display: inline-block;
44
+  }
45
+
46
+  .user-info {
47
+    cursor: pointer;
48
+
49
+    .ant-avatar {
50
+      border: 1px solid rgba(255, 255, 255, 0.4);
51
+    }
52
+
53
+    span {
54
+      margin-left: 1em;
55
+    }
56
+  }
57
+
58
+  .sys-exit {
59
+    margin-right: 1em;
60
+  }
61
+}
62
+
63
+.logo {
64
+  height: var(--header-height);
65
+  display: flex;
66
+  align-items: center;
67
+  box-sizing: border-box;
68
+  padding-left: 1em;
69
+  color: inherit;
70
+
71
+  & > * {
72
+    color: inherit;
73
+    margin: 0;
74
+  }
75
+
76
+  h5 {
77
+    margin: 0;
78
+  }
79
+
80
+  img {
81
+    height: 52px;
82
+    vertical-align: middle;
83
+    margin-right: 1em;
84
+  }
85
+}
86
+
87
+.layout-sidebar {
88
+  background: #0D267C;
89
+
90
+  .ant-menu-item-selected {
91
+    background: #4276F5 !important;
92
+  }
93
+}
94
+
95
+.layout-container {
96
+  flex: 1;
97
+
98
+  overflow-y: auto;
99
+  scrollbar-width: none;
100
+  -ms-overflow-style: none;
101
+
102
+  &::--webkit-scrollbar {
103
+    display: none;
104
+  }
105
+}

+ 21
- 0
src/layouts/AuthLayout/useReady.jsx Zobrazit soubor

@@ -0,0 +1,21 @@
1
+import React, { useState, useEffect } from 'react';
2
+import { useNavigate, useHref } from "react-router-dom";
3
+import { queryCurrentUser } from '@/services/user';
4
+
5
+export default function useReady({ user, setUser }) {
6
+  const navigate = useNavigate();
7
+  const isLogined = user && user.id;
8
+
9
+  useEffect(() => {
10
+    if (!isLogined) {
11
+      queryCurrentUser().then((res) => {
12
+        setUser(res);
13
+      }).catch(err => {
14
+        const { data } = err;
15
+        if (data.code === 1001) {
16
+          navigate('/login?back=true');
17
+        }
18
+      });
19
+    }
20
+  }, [isLogined]);
21
+}

+ 15
- 0
src/layouts/Container.jsx Zobrazit soubor

@@ -0,0 +1,15 @@
1
+import React from 'react';
2
+import { Outlet } from 'react-router-dom';
3
+
4
+const containerStyle = {
5
+  margin: '24px 24px 0 24px',
6
+  height: '100%',
7
+}
8
+
9
+export default (props) => {
10
+  return (
11
+    <div style={containerStyle}>
12
+      <Outlet />
13
+    </div>
14
+  )
15
+}

+ 11
- 0
src/main.jsx Zobrazit soubor

@@ -0,0 +1,11 @@
1
+import React from 'react'
2
+import ReactDOM from 'react-dom/client';
3
+import Router from './routes/Router';
4
+import './index.less'
5
+import { Provider } from './store';
6
+
7
+ReactDOM.createRoot(document.getElementById('root')).render(
8
+  <Provider>
9
+    <Router />
10
+  </Provider>
11
+)

+ 0
- 22
src/manifest.json Zobrazit soubor

@@ -1,22 +0,0 @@
1
-{
2
-  "name": "Ant Design Pro",
3
-  "short_name": "Ant Design Pro",
4
-  "display": "standalone",
5
-  "start_url": "./?utm_source=homescreen",
6
-  "theme_color": "#002140",
7
-  "background_color": "#001529",
8
-  "icons": [
9
-    {
10
-      "src": "icons/icon-192x192.png",
11
-      "sizes": "192x192"
12
-    },
13
-    {
14
-      "src": "icons/icon-128x128.png",
15
-      "sizes": "128x128"
16
-    },
17
-    {
18
-      "src": "icons/icon-512x512.png",
19
-      "sizes": "512x512"
20
-    }
21
-  ]
22
-}

+ 0
- 18
src/pages/404.jsx Zobrazit soubor

@@ -1,18 +0,0 @@
1
-import { history } from '@umijs/max';
2
-import { Button, Result } from 'antd';
3
-import React from 'react';
4
-
5
-const NoFoundPage= () => (
6
-  <Result
7
-    status="404"
8
-    title="404"
9
-    subTitle="Sorry, the page you visited does not exist."
10
-    extra={
11
-      <Button type="primary" onClick={() => history.push('/')}>
12
-        Back Home
13
-      </Button>
14
-    }
15
-  />
16
-);
17
-
18
-export default NoFoundPage;

+ 29
- 0
src/pages/404/index.jsx Zobrazit soubor

@@ -0,0 +1,29 @@
1
+import React from 'react';
2
+import { Button, Result } from 'antd';
3
+import { Helmet } from "react-helmet";
4
+import { NavLink } from "react-router-dom";
5
+import { useModel } from '@/store';
6
+
7
+const style = {
8
+  display: 'grid',
9
+  placeItems: 'center',
10
+  height: '100%'
11
+}
12
+
13
+export default (props) => {
14
+  const { app } = useModel('system');
15
+
16
+  return (
17
+    <div style={style}>
18
+      <Helmet>
19
+        <title>{app.fullName}</title>
20
+      </Helmet>
21
+      <Result
22
+        status="404"
23
+        title="404"
24
+        subTitle="页面不存在"
25
+        extra={<NavLink to="/" replace><Button type="primary">返回首页</Button></NavLink>}
26
+      />
27
+    </div>
28
+  )
29
+}

+ 0
- 45
src/pages/Admin.jsx Zobrazit soubor

@@ -1,45 +0,0 @@
1
-import { HeartTwoTone, SmileTwoTone } from '@ant-design/icons';
2
-import { PageHeaderWrapper } from '@ant-design/pro-components';
3
-import { useIntl } from '@umijs/max';
4
-import { Alert, Card, Typography } from 'antd';
5
-import React from 'react';
6
-
7
-const Admin = () => {
8
-  const intl = useIntl();
9
-  return (
10
-    <PageHeaderWrapper
11
-      content={intl.formatMessage({
12
-        id: 'pages.admin.subPage.title',
13
-        defaultMessage: 'This page can only be viewed by admin',
14
-      })}
15
-    >
16
-      <Card>
17
-        <Alert
18
-          message={intl.formatMessage({
19
-            id: 'pages.welcome.alertMessage',
20
-            defaultMessage: 'Faster and stronger heavy-duty components have been released.',
21
-          })}
22
-          type="success"
23
-          showIcon
24
-          banner
25
-          style={{
26
-            margin: -12,
27
-            marginBottom: 48,
28
-          }}
29
-        />
30
-        <Typography.Title level={2} style={{ textAlign: 'center' }}>
31
-          <SmileTwoTone /> Ant Design Pro <HeartTwoTone twoToneColor="#eb2f96" /> You
32
-        </Typography.Title>
33
-      </Card>
34
-      <p style={{ textAlign: 'center', marginTop: 24 }}>
35
-        Want to add more pages? Please refer to{' '}
36
-        <a href="https://pro.ant.design/docs/block-cn" target="_blank" rel="noopener noreferrer">
37
-          use block
38
-        </a>
39
-        。
40
-      </p>
41
-    </PageHeaderWrapper>
42
-  );
43
-};
44
-
45
-export default Admin;

+ 0
- 17
src/pages/Welcome.jsx Zobrazit soubor

@@ -1,17 +0,0 @@
1
-import { PageContainer } from '@ant-design/pro-components';
2
-import { Typography } from 'antd';
3
-import styles from './Welcome.less';
4
-
5
-const CodePreview = ({ children }) => (
6
-  <pre className={styles.pre}>
7
-    <code>
8
-      <Typography.Text copyable>{children}</Typography.Text>
9
-    </code>
10
-  </pre>
11
-);
12
-
13
-const Welcome = () => {
14
-  return <PageContainer>234</PageContainer>;
15
-};
16
-
17
-export default Welcome;

+ 0
- 8
src/pages/Welcome.less Zobrazit soubor

@@ -1,8 +0,0 @@
1
-@import (reference) '~antd/es/style/themes/index';
2
-
3
-.pre {
4
-  margin: 12px 0;
5
-  padding: 12px 20px;
6
-  background: @input-bg;
7
-  box-shadow: @card-shadow;
8
-}

+ 6
- 5
src/pages/dish/edit/index.jsx Zobrazit soubor

@@ -1,7 +1,7 @@
1
-import { addDish, getDishById } from '@/services/api/dish';
2
-import { getStoreList } from '@/services/api/stock';
1
+import { addDish, getDishById } from '@/services/dish';
2
+import { getStoreList } from '@/services/stock';
3 3
 import { PageContainer, ProForm, ProFormSelect, ProFormText } from '@ant-design/pro-components';
4
-import { history, useSearchParams } from '@umijs/max';
4
+import { useNavigate, useSearchParams } from 'react-router-dom';
5 5
 import { Card, Col, message, Row, Space } from 'antd';
6 6
 import { useEffect, useRef, useState } from 'react';
7 7
 
@@ -9,6 +9,7 @@ export default (props) => {
9 9
   const [searchParams] = useSearchParams();
10 10
   const id = searchParams.get('id');
11 11
   const [foodDict, setFoodDict] = useState([]);
12
+  const navigate = useNavigate();
12 13
 
13 14
   const formRef = useRef();
14 15
   useEffect(() => {
@@ -35,7 +36,7 @@ export default (props) => {
35 36
 
36 37
     addDish({ ...values, id }).then((res) => {
37 38
       message.success('添加成功');
38
-      history.back();
39
+      navigate(-1);
39 40
     });
40 41
 
41 42
     return false;
@@ -55,7 +56,7 @@ export default (props) => {
55 56
             searchConfig: {
56 57
               resetText: '返回',
57 58
             },
58
-            onReset: () => history.back(),
59
+            onReset: () => navigate(-1),
59 60
             render: (props, doms) => {
60 61
               return (
61 62
                 <Row>

+ 6
- 5
src/pages/dish/list/index.jsx Zobrazit soubor

@@ -1,8 +1,8 @@
1
-import { getDishList, addDish, updataDish, deleteDish } from '@/services/api/dish';
1
+import { getDishList, addDish, updataDish, deleteDish } from '@/services/dish';
2 2
 import { queryTable } from '@/utils/request';
3 3
 import { PageContainer, ProTable } from '@ant-design/pro-components';
4
-import { history } from '@umijs/max';
5
-import { Button, message, Popconfirm, EditForm } from 'antd';
4
+import { useNavigate } from 'react-router-dom';
5
+import { Button, message, Popconfirm } from 'antd';
6 6
 import { useRef, useState } from 'react';
7 7
 
8 8
 const DishList = (props) => {
@@ -10,6 +10,7 @@ const DishList = (props) => {
10 10
   const [showDetail, setShowDetail] = useState(false);
11 11
   const [activeKey, setActiveKey] = useState('');
12 12
   const actionRef = useRef();
13
+  const navigate = useNavigate();
13 14
 
14 15
   const updata = (row) => {
15 16
     if (row.id) {
@@ -56,7 +57,7 @@ const DishList = (props) => {
56 57
           style={{ padding: 0 }}
57 58
           type="link"
58 59
           onClick={() => {
59
-            history.push(`/dish/add?id=${record.id}`);
60
+            navigate(`/material/dish/edit?id=${record.id}`);
60 61
           }}
61 62
         >
62 63
           修改
@@ -89,7 +90,7 @@ const DishList = (props) => {
89 90
             key="2"
90 91
             type="primary"
91 92
             onClick={() => {
92
-              history.push('/dish/add');
93
+              navigate('/material/dish/edit');
93 94
             }}
94 95
           >
95 96
             新增

+ 0
- 236
src/pages/document.ejs Zobrazit soubor

@@ -1,236 +0,0 @@
1
-<!DOCTYPE html>
2
-<html lang="en">
3
-  <head>
4
-    <meta charset="UTF-8" />
5
-    <meta name="theme-color" content="#1890ff" />
6
-    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
7
-    <meta
8
-      name="keywords"
9
-      content="antd,umi,umijs,ant design,Scaffolding, layout, Ant Design, project, Pro, admin, console, homepage, out-of-the-box, middle and back office, solution, component library"
10
-    />
11
-    <meta
12
-      name="description"
13
-      content="
14
-    An out-of-box UI solution for enterprise applications as a React boilerplate."
15
-    />
16
-    <meta
17
-      name="description"
18
-      content="
19
-      Out-of-the-box mid-stage front-end/design solution."
20
-    />
21
-    <meta
22
-      name="viewport"
23
-      content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
24
-    />
25
-    <title>军供</title>
26
-    <link rel="icon" href="<%= context.config.publicPath +'favicon.ico'%>" type="image/x-icon" />
27
-  </head>
28
-  <body>
29
-    <noscript>
30
-      <div class="noscript-container">
31
-        Hi there! Please
32
-        <div class="noscript-enableJS">
33
-          <a href="https://www.enablejavascript.io/en" target="_blank" rel="noopener noreferrer">
34
-            <b>enable Javascript</b>
35
-          </a>
36
-        </div>
37
-        in your browser to use Ant Design, Out-of-the-box mid-stage front/design solution!
38
-      </div>
39
-    </noscript>
40
-    <div id="root">
41
-      <style>
42
-        html,
43
-        body,
44
-        #root {
45
-          height: 100%;
46
-          margin: 0;
47
-          padding: 0;
48
-        }
49
-        #root {
50
-          background-repeat: no-repeat;
51
-          background-size: 100% auto;
52
-        }
53
-        .noscript-container {
54
-          display: flex;
55
-          align-content: center;
56
-          justify-content: center;
57
-          margin-top: 90px;
58
-          font-size: 20px;
59
-          font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode',
60
-            Geneva, Verdana, sans-serif;
61
-        }
62
-        .noscript-enableJS {
63
-          padding-right: 3px;
64
-          padding-left: 3px;
65
-        }
66
-        .page-loading-warp {
67
-          display: flex;
68
-          align-items: center;
69
-          justify-content: center;
70
-          padding: 98px;
71
-        }
72
-        .ant-spin {
73
-          position: absolute;
74
-          display: none;
75
-          -webkit-box-sizing: border-box;
76
-          box-sizing: border-box;
77
-          margin: 0;
78
-          padding: 0;
79
-          color: rgba(0, 0, 0, 0.65);
80
-          color: #1890ff;
81
-          font-size: 14px;
82
-          font-variant: tabular-nums;
83
-          line-height: 1.5;
84
-          text-align: center;
85
-          list-style: none;
86
-          opacity: 0;
87
-          -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
88
-          transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
89
-          transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
90
-          transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
91
-            -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
92
-          -webkit-font-feature-settings: 'tnum';
93
-          font-feature-settings: 'tnum';
94
-        }
95
-
96
-        .ant-spin-spinning {
97
-          position: static;
98
-          display: inline-block;
99
-          opacity: 1;
100
-        }
101
-
102
-        .ant-spin-dot {
103
-          position: relative;
104
-          display: inline-block;
105
-          width: 20px;
106
-          height: 20px;
107
-          font-size: 20px;
108
-        }
109
-
110
-        .ant-spin-dot-item {
111
-          position: absolute;
112
-          display: block;
113
-          width: 9px;
114
-          height: 9px;
115
-          background-color: #1890ff;
116
-          border-radius: 100%;
117
-          -webkit-transform: scale(0.75);
118
-          -ms-transform: scale(0.75);
119
-          transform: scale(0.75);
120
-          -webkit-transform-origin: 50% 50%;
121
-          -ms-transform-origin: 50% 50%;
122
-          transform-origin: 50% 50%;
123
-          opacity: 0.3;
124
-          -webkit-animation: antspinmove 1s infinite linear alternate;
125
-          animation: antSpinMove 1s infinite linear alternate;
126
-        }
127
-
128
-        .ant-spin-dot-item:nth-child(1) {
129
-          top: 0;
130
-          left: 0;
131
-        }
132
-
133
-        .ant-spin-dot-item:nth-child(2) {
134
-          top: 0;
135
-          right: 0;
136
-          -webkit-animation-delay: 0.4s;
137
-          animation-delay: 0.4s;
138
-        }
139
-
140
-        .ant-spin-dot-item:nth-child(3) {
141
-          right: 0;
142
-          bottom: 0;
143
-          -webkit-animation-delay: 0.8s;
144
-          animation-delay: 0.8s;
145
-        }
146
-
147
-        .ant-spin-dot-item:nth-child(4) {
148
-          bottom: 0;
149
-          left: 0;
150
-          -webkit-animation-delay: 1.2s;
151
-          animation-delay: 1.2s;
152
-        }
153
-
154
-        .ant-spin-dot-spin {
155
-          -webkit-transform: rotate(45deg);
156
-          -ms-transform: rotate(45deg);
157
-          transform: rotate(45deg);
158
-          -webkit-animation: antrotate 1.2s infinite linear;
159
-          animation: antRotate 1.2s infinite linear;
160
-        }
161
-
162
-        .ant-spin-lg .ant-spin-dot {
163
-          width: 32px;
164
-          height: 32px;
165
-          font-size: 32px;
166
-        }
167
-
168
-        .ant-spin-lg .ant-spin-dot i {
169
-          width: 14px;
170
-          height: 14px;
171
-        }
172
-
173
-        @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
174
-          .ant-spin-blur {
175
-            background: #fff;
176
-            opacity: 0.5;
177
-          }
178
-        }
179
-
180
-        @-webkit-keyframes antSpinMove {
181
-          to {
182
-            opacity: 1;
183
-          }
184
-        }
185
-
186
-        @keyframes antSpinMove {
187
-          to {
188
-            opacity: 1;
189
-          }
190
-        }
191
-
192
-        @-webkit-keyframes antRotate {
193
-          to {
194
-            -webkit-transform: rotate(405deg);
195
-            transform: rotate(405deg);
196
-          }
197
-        }
198
-
199
-        @keyframes antRotate {
200
-          to {
201
-            -webkit-transform: rotate(405deg);
202
-            transform: rotate(405deg);
203
-          }
204
-        }
205
-      </style>
206
-      <div
207
-        style="
208
-          display: flex;
209
-          flex-direction: column;
210
-          align-items: center;
211
-          justify-content: center;
212
-          height: 100%;
213
-          min-height: 420px;
214
-        "
215
-      >
216
-        <img src="<%= context.config.publicPath +'pro_icon.svg'%>" alt="logo" width="256" />
217
-        <div class="page-loading-warp">
218
-          <div class="ant-spin ant-spin-lg ant-spin-spinning">
219
-            <span class="ant-spin-dot ant-spin-dot-spin"
220
-              ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
221
-              ><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
222
-            ></span>
223
-          </div>
224
-        </div>
225
-        <div style="display: flex; align-items: center; justify-content: center">
226
-          <img
227
-            src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
228
-            width="32"
229
-            style="margin-right: 8px"
230
-          />
231
-          Ant Design
232
-        </div>
233
-      </div>
234
-    </div>
235
-  </body>
236
-</html>

+ 5
- 5
src/pages/guaranteeTask/Edit/BasicForm.jsx Zobrazit soubor

@@ -1,9 +1,8 @@
1 1
 import React, { useState, useEffect } from 'react';
2 2
 import moment from 'moment';
3
-import { Link } from 'umi';
4
-import { history } from '@umijs/max';
3
+import { Link, useNavigate } from 'react-router-dom';
5 4
 import { Button, Row, Col, Form, Input, InputNumber, DatePicker, notification } from 'antd';
6
-import { addGuaranteeTask, updateGuaranteeTask } from '@/services/api/guaranteeTask';
5
+import { addGuaranteeTask, updateGuaranteeTask } from '@/services/guaranteeTask';
7 6
 
8 7
 const { TextArea } = Input;
9 8
 const { RangePicker } = DatePicker;
@@ -12,7 +11,8 @@ export default (props) => {
12 11
   const { dataSource, setDataSource } = props;
13 12
   const id = dataSource ? dataSource.id : undefined;
14 13
 
15
-  const [form] = Form.useForm()
14
+  const navigate = useNavigate();
15
+  const [form] = Form.useForm();
16 16
   const [rangeDate, setRangeDate] = useState([]);
17 17
   const [loading, setLoading] = useState(false);
18 18
 
@@ -200,7 +200,7 @@ export default (props) => {
200 200
       <Row gutter={48}>
201 201
         <Col offset={6} span={12}>
202 202
           <Button type="primary" htmlType="submit" loading={loading}>提交</Button>
203
-          <Button style={{ marginLeft: '48px' }} onClick={() => history.back()}>返回</Button>
203
+          <Button style={{ marginLeft: '48px' }} onClick={() => navigate(-1)}>返回</Button>
204 204
           <Button style={{ marginLeft: '48px' }}>
205 205
             <Link target="_blank" to={`/guaranteeTask/print?id=${id}`}>打印预览</Link>
206 206
           </Button>

+ 3
- 3
src/pages/guaranteeTask/Edit/DishList.jsx Zobrazit soubor

@@ -1,14 +1,14 @@
1 1
 import React, { useState, useEffect, useRef } from 'react';
2 2
 import { Row, Col, Card, Button, notification } from 'antd';
3 3
 import EditableTag from '@/components/EditableTag';
4
-import { getDishList } from '@/services/api/dish';
5
-import { getPackageList, getPackageDetailList } from '@/services/api/package';
4
+import { getDishList } from '@/services/dish';
5
+import { getPackageList, getPackageDetailList } from '@/services/package';
6 6
 import {
7 7
   updateGuaranteeTask,
8 8
   getGuaranteeDetailList,
9 9
   addGuaranteeDetailBatch,
10 10
   deleteGuaranteeDetail
11
-} from '@/services/api/guaranteeTask';
11
+} from '@/services/guaranteeTask';
12 12
 import Selector from './components/Selector';
13 13
 
14 14
 export default (props) => {

+ 2
- 2
src/pages/guaranteeTask/Edit/index.jsx Zobrazit soubor

@@ -1,8 +1,8 @@
1 1
 import React, { useState, useEffect } from 'react';
2
-import { useSearchParams } from '@umijs/max';
2
+import { useSearchParams } from 'react-router-dom';
3 3
 import { Tabs, Card } from 'antd';
4 4
 import { PageContainer } from '@ant-design/pro-components';
5
-import { getGuaranteeTask } from '@/services/api/guaranteeTask';
5
+import { getGuaranteeTask } from '@/services/guaranteeTask';
6 6
 import BasicForm from './BasicForm';
7 7
 import DishList from './DishList';
8 8
 

+ 6
- 5
src/pages/guaranteeTask/index.jsx Zobrazit soubor

@@ -1,13 +1,14 @@
1
-import { deleteGuaranteeTask, getGuaranteeTaskList } from '@/services/api/guaranteeTask';
1
+import { deleteGuaranteeTask, getGuaranteeTaskList } from '@/services/guaranteeTask';
2 2
 import { queryTable } from '@/utils/request';
3 3
 import { PageContainer, ProTable } from '@ant-design/pro-components';
4
-import { Link } from 'umi';
5
-import { history } from '@umijs/max';
4
+import { Link, useNavigate } from 'react-router-dom';
5
+
6 6
 import { Button, message, Popconfirm } from 'antd';
7 7
 import moment from 'moment';
8 8
 import { useRef, useState } from 'react';
9 9
 
10 10
 const GuaranteeTaskList = (props) => {
11
+  const navigate = useNavigate();
11 12
   const [isOpen, setIsOpen] = useState(false);
12 13
   const [modalData, setModalData] = useState({});
13 14
   // const [storeTypeDict, setStoreTypeDict] = useState([]);
@@ -78,7 +79,7 @@ const GuaranteeTaskList = (props) => {
78 79
           style={{ padding: 0 }}
79 80
           type="link"
80 81
           onClick={() => {
81
-            history.push(`/guaranteeTask/edit?id=${record.id}`);
82
+            navigate(`/task/guaranteeTask/edit?id=${record.id}`);
82 83
           }}
83 84
         >
84 85
           修改
@@ -101,7 +102,7 @@ const GuaranteeTaskList = (props) => {
101 102
           style={{ padding: 0 }}
102 103
           type="link"
103 104
         >
104
-          <Link target="_blank" to={`/guaranteeTask/print?id=${record.id}`}>打印</Link>
105
+          <Link target="_blank" to={`/task/guaranteeTask/print?id=${record.id}`}>打印</Link>
105 106
         </Button>,
106 107
       ],
107 108
     },

+ 3
- 3
src/pages/guaranteeTask/print/index.jsx Zobrazit soubor

@@ -1,9 +1,9 @@
1 1
 import React, { useRef, useState, useEffect } from 'react';
2 2
 import moment from 'moment';
3 3
 import { Button } from 'antd';
4
-import { useSearchParams } from '@umijs/max';
5
-import { getGuaranteeTask } from '@/services/api/guaranteeTask';
6
-import { getGuaranteeDetailList } from '@/services/api/guaranteeTask';
4
+import { useSearchParams } from 'react-router-dom';
5
+import { getGuaranteeTask } from '@/services/guaranteeTask';
6
+import { getGuaranteeDetailList } from '@/services/guaranteeTask';
7 7
 import Styles from './style.less';
8 8
 
9 9
 export default (props) => {

src/pages/User/Login/index.jsx → src/pages/login/index.jsx Zobrazit soubor

@@ -1,11 +1,10 @@
1
-import Footer from '@/components/Footer';
2
-import { login } from '@/services/api/user';
3
-import { LockOutlined, UserOutlined } from '@ant-design/icons';
4
-import { LoginForm, ProFormText } from '@ant-design/pro-components';
5
-import { history, useModel } from '@umijs/max';
6
-import { Alert, message, Form, Button, Input } from 'antd';
7 1
 import { useState } from 'react';
2
+import { useNavigate, useParams } from "react-router-dom";
3
+import { login } from '@/services/user';
4
+import { LockOutlined, UserOutlined } from '@ant-design/icons';
5
+import { message, Form, Button, Input } from 'antd';
8 6
 import md5 from 'md5';
7
+import { useModel } from '@/store';
9 8
 import Logo from '@/assets/images/logo.png';
10 9
 import decorateLeft from '@/assets/images/login/装饰左.png';
11 10
 import decorateRight from '@/assets/images/login/装饰右.png';
@@ -14,9 +13,11 @@ import './index.less';
14 13
 const errStyle = {color: 'red', paddingBottom: '10px'}
15 14
 
16 15
 const Login = () => {
17
-  const [type, setType] = useState('account');
18
-  const { initialState, setInitialState } = useModel('@@initialState');
19
-  const [errMsg, setErrMsg] = useState()
16
+  const urlParams = useParams();
17
+  const { setUser } = useModel('user');
18
+  const [errMsg, setErrMsg] = useState();
19
+
20
+  const navigate = useNavigate();
20 21
 
21 22
   const handleSubmit = async (values) => {
22 23
     try {
@@ -27,22 +28,20 @@ const Login = () => {
27 28
       const defaultLoginSuccessMessage = '登录成功!';
28 29
       message.success(defaultLoginSuccessMessage);
29 30
       
30
-      setInitialState({
31
-        currentUser: res.user,
32
-      });
33
-      
34
-      const urlParams = new URL(window.location.href).searchParams;
35
-      history.push(urlParams.get('redirect') || '/');
36
-      return;
37
-
38
-      
31
+      setUser(res.user);      
32
+      if (urlParams.back) {
33
+        navigate(-1);
34
+      } else {
35
+        navigate('/');
36
+      }
37
+      return;      
39 38
     } catch (error) {
40 39
       console.log(error);
41 40
     }
42 41
   };
43 42
 
44 43
   return (
45
-    <div className="page-container">
44
+    <div className="login-container">
46 45
       <Form name="login" id="login" onFinish={handleSubmit}>
47 46
         <div className="form-left">
48 47
           <img src={Logo} />

src/pages/User/Login/index.less → src/pages/login/index.less Zobrazit soubor

@@ -4,10 +4,10 @@ html, body {
4 4
   margin: 0;
5 5
 }
6 6
 
7
-.page-container {
7
+.login-container {
8 8
   width: 100%;
9 9
   height: 100%;
10
-  background-image: url(~@/assets/images/login/background.png);
10
+  background-image: url(@/assets/images/login/background.png);
11 11
   background-repeat: no-repeat;
12 12
   background-size: cover;
13 13
   display: flex;
@@ -26,7 +26,7 @@ html, body {
26 26
     .form-left {
27 27
       flex: 2;
28 28
       height: 480px;
29
-      background-image: url(~@/assets/images/login/小背景.png);
29
+      background-image: url(@/assets/images/login/小背景.png);
30 30
       background-color: transparent;
31 31
       background-repeat: no-repeat;
32 32
       background-size: cover;

+ 0
- 43
src/pages/monitor/edit.jsx Zobrazit soubor

@@ -1,43 +0,0 @@
1
-import {
2
-  ModalForm,
3
-  ProFormText,
4
-} from '@ant-design/pro-components';
5
-import { Button, Form, message } from 'antd';
6
-import { useEffect } from 'react';
7
-
8
-export default (props) => {
9
-  const { onSubmit, onCancel, dataSource = {}, visible } = props;
10
-  const [form] = Form.useForm();
11
-
12
-  const handleSubmit = (values) => {
13
-    if (typeof onSubmit === 'function') {
14
-      onSubmit({
15
-        status: '1',
16
-        ...(dataSource || {}),
17
-        ...values
18
-
19
-      })
20
-    }
21
-  }
22
-
23
-  useEffect(() => {
24
-    console.log('----------', dataSource.title)
25
-    form.setFieldsValue({ title: dataSource.title, url: dataSource.url })
26
-  }, [dataSource.title, dataSource.url, form])
27
-
28
-  return (
29
-    <ModalForm
30
-      title="新建表单"
31
-      visible={visible}
32
-      form={form}
33
-      modalProps={{
34
-        destroyOnClose: true,
35
-        onCancel: onCancel,
36
-      }}
37
-      onFinish={handleSubmit}
38
-    >
39
-      <ProFormText name="title" label="监控名称" />
40
-      <ProFormText name="url" label="视频地址" />
41
-    </ModalForm>
42
-  );
43
-};

+ 0
- 151
src/pages/monitor/index.jsx Zobrazit soubor

@@ -1,151 +0,0 @@
1
-import { deleteMonitor, getMonitorList, updataMonitor, addMonitor } from '@/services/api/monitor';
2
-import { queryTable } from '@/utils/request';
3
-import { PageContainer, ProTable } from '@ant-design/pro-components';
4
-import { history } from '@umijs/max';
5
-import { Button, message, Popconfirm } from 'antd';
6
-import { useRef, useState } from 'react';
7
-import EditForm from './edit'
8
-
9
-const List = (props) => {
10
-  console.log(props, '===');
11
-  const [visible, setVisible] = useState(false);
12
-  const [current, setCurrent] = useState({});
13
-  const [activeKey, setActiveKey] = useState('');
14
-  const actionRef = useRef();
15
-
16
-  const updata = (row) => {
17
-    if (row.id) {
18
-      updataMonitor(row.id, { status: row.status === '1' ? '2' : '1' }).then((res) => {
19
-        message.success('修改成功');
20
-        actionRef.current.reload();
21
-      });
22
-    }
23
-  };
24
-
25
-  const onSubmit = (values) => {
26
-    if (!Object.prototype.hasOwnProperty.call(values, 'id')) {
27
-      addMonitor(values).then((res) => {
28
-        setCurrent(res);
29
-        setVisible(false);
30
-        message.success('操作成功');
31
-        actionRef.current.reload();
32
-      })
33
-    } else {
34
-      updataMonitor(values.id, values).then((res) => {
35
-        setVisible(false);
36
-        message.success('操作成功');
37
-        actionRef.current.reload();
38
-      });
39
-    }
40
-  }
41
-
42
-  const handleDelete = (id) => {
43
-    if (id) {
44
-      deleteMonitor(id).then((res) => {
45
-        message.success('删除成功');
46
-        actionRef.current.reload();
47
-      });
48
-    }
49
-  };
50
-
51
-  const columns = [
52
-    {
53
-      title: 'id',
54
-      dataIndex: 'id',
55
-    },
56
-    {
57
-      title: '监控',
58
-      dataIndex: 'title',
59
-    },
60
-    {
61
-      title: '地址',
62
-      dataIndex: 'url',
63
-    },
64
-    {
65
-      title: '状态',
66
-      dataIndex: 'status',
67
-      valueEnum: {
68
-        1: {
69
-          text: '上架',
70
-          status: 'Processing',
71
-        },
72
-        2: {
73
-          text: '下架',
74
-          status: 'Error',
75
-        },
76
-      },
77
-    },
78
-    {
79
-      title: '操作',
80
-      valueType: 'option',
81
-      width: 200,
82
-      render: (_, record) => [
83
-        <Button
84
-          key={1}
85
-          style={{ padding: 0 }}
86
-          type="link"
87
-          onClick={() => {
88
-            updata(record);
89
-          }}
90
-        >
91
-          {record.status === '1' ? '下架' : '上架'}
92
-        </Button>,
93
-        <Button
94
-          key={2}
95
-          style={{ padding: 0 }}
96
-          type="link"
97
-          onClick={() => {
98
-            setCurrent(record);
99
-            setVisible(true);
100
-          }}
101
-        >
102
-          编辑
103
-        </Button>,
104
-
105
-        <Popconfirm
106
-          key={3}
107
-          title="您是否确认删除 ?"
108
-          onConfirm={() => handleDelete(record.id)}
109
-          okText="确定"
110
-          cancelText="取消"
111
-        >
112
-          {/* manualPush */}
113
-          <Button style={{ padding: 0 }} type="link">
114
-            删除
115
-          </Button>
116
-        </Popconfirm>,
117
-      ],
118
-    },
119
-  ];
120
-
121
-  return (
122
-    <PageContainer>
123
-      <EditForm
124
-        visible={visible}
125
-        dataSource={current}
126
-        onCancel={() => setVisible(false)}
127
-        onSubmit={onSubmit}
128
-      />
129
-      <ProTable
130
-        // headerTitle={'中高风险地区库'}
131
-        search={false}
132
-        actionRef={actionRef}
133
-        rowKey="id"
134
-        toolBarRender={() => [
135
-          <Button
136
-            key="2"
137
-            type="primary"
138
-            onClick={() => { setCurrent({}); setVisible(true); }}
139
-          >
140
-            新增
141
-          </Button>,
142
-        ]}
143
-        // search={false}
144
-        request={queryTable(getMonitorList)}
145
-        columns={columns}
146
-      />
147
-    </PageContainer>
148
-  );
149
-};
150
-
151
-export default List;

+ 1
- 1
src/pages/package/BasicForm.jsx Zobrazit soubor

@@ -1,6 +1,6 @@
1 1
 import React, { useState, useEffect } from 'react';
2 2
 import { Button, Checkbox, Card, Form, Input, notification } from 'antd';
3
-import { addPackage, updataPackage } from '@/services/api/package';
3
+import { addPackage, updataPackage } from '@/services/package';
4 4
 
5 5
 export default (props) => {
6 6
   const { current, onChange } = props;

+ 2
- 2
src/pages/package/DishList.jsx Zobrazit soubor

@@ -1,8 +1,8 @@
1 1
 import React, { useEffect, useState, useRef } from 'react';
2 2
 import { Button, List, Popconfirm, Select } from 'antd';
3 3
 import classNames from 'classnames';
4
-import { getPackageDetailList, addPackageDetail, deletePackageDetail } from '@/services/api/package';
5
-import { getDishList } from '@/services/api/dish';
4
+import { getPackageDetailList, addPackageDetail, deletePackageDetail } from '@/services/package';
5
+import { getDishList } from '@/services/dish';
6 6
 
7 7
 const { Option } = Select;
8 8
 

+ 1
- 1
src/pages/package/List.jsx Zobrazit soubor

@@ -1,7 +1,7 @@
1 1
 import React, { useState, useEffect, useRef } from 'react';
2 2
 import { Row, Col, Button, List, Popconfirm, Input } from 'antd';
3 3
 import classNames from 'classnames';
4
-import { getPackageList, deletePackage } from '@/services/api/package';
4
+import { getPackageList, deletePackage } from '@/services/package';
5 5
 
6 6
 export default (props) => {
7 7
   const { current, setCurrent } = props;

+ 7
- 5
src/pages/rotationChart/edit/index.jsx Zobrazit soubor

@@ -1,7 +1,7 @@
1 1
 import UploadImage from '@/components/UploadImage';
2 2
 import UploadVideo from '@/components/UploadVideo';
3 3
 import UploadFile from '@/components/UploadFile';
4
-import { addBanner, getBannerdById, updataBanner } from '@/services/api/rotationChart';
4
+import { addBanner, getBannerdById, updataBanner } from '@/services/rotationChart';
5 5
 import {
6 6
   PageContainer,
7 7
   ProForm,
@@ -10,7 +10,7 @@ import {
10 10
   ProFormSelect,
11 11
   ProFormTextArea,
12 12
 } from '@ant-design/pro-components';
13
-import { history, useSearchParams } from '@umijs/max';
13
+import { useNavigate, useSearchParams } from 'react-router-dom';
14 14
 import { Card, Col, message, Row, Space, Image } from 'antd';
15 15
 import { useEffect, useRef, useState } from 'react';
16 16
 
@@ -20,6 +20,8 @@ export default (props) => {
20 20
   const [data, setData] = useState({});
21 21
   const [imgLabel, setImgLabel] = useState('图片');
22 22
   const formRef = useRef();
23
+  const navigate = useNavigate();
24
+
23 25
   useEffect(() => {
24 26
     if (id) {
25 27
       getBannerdById(id).then((res) => {
@@ -35,13 +37,13 @@ export default (props) => {
35 37
       // 修改
36 38
       updataBanner(id, { ...values }).then((res) => {
37 39
         message.success('修改成功');
38
-        history.back();
40
+        navigate(-1);
39 41
       });
40 42
     } else {
41 43
       // 新增
42 44
       addBanner({ ...values }).then((res) => {
43 45
         message.success('添加成功');
44
-        history.back();
46
+        navigate(-1);
45 47
       });
46 48
     }
47 49
 
@@ -62,7 +64,7 @@ export default (props) => {
62 64
             searchConfig: {
63 65
               resetText: '返回',
64 66
             },
65
-            onReset: () => history.back(),
67
+            onReset: () => navigate(-1),
66 68
             render: (props, doms) => {
67 69
               return (
68 70
                 <Row>

+ 5
- 4
src/pages/rotationChart/list/index.jsx Zobrazit soubor

@@ -1,7 +1,7 @@
1
-import { deleteBanner, getBannerList, updataBanner } from '@/services/api/rotationChart';
1
+import { deleteBanner, getBannerList, updataBanner } from '@/services/rotationChart';
2 2
 import { queryTable } from '@/utils/request';
3 3
 import { PageContainer, ProTable } from '@ant-design/pro-components';
4
-import { history } from '@umijs/max';
4
+import { useNavigate } from 'react-router-dom';
5 5
 import { Button, message, Popconfirm } from 'antd';
6 6
 import { useRef, useState } from 'react';
7 7
 
@@ -10,6 +10,7 @@ const RotationChartList = (props) => {
10 10
   const [showDetail, setShowDetail] = useState(false);
11 11
   const [activeKey, setActiveKey] = useState('');
12 12
   const actionRef = useRef();
13
+  const navigate = useNavigate();
13 14
 
14 15
   const updata = (row) => {
15 16
     if (row.id) {
@@ -97,7 +98,7 @@ const RotationChartList = (props) => {
97 98
           type="link"
98 99
           onClick={() => {
99 100
             console.log(record, ']]');
100
-            history.push(`/rotationChart/add?id=${record.id}`);
101
+            navigate(`/cms/rotationChart/add?id=${record.id}`);
101 102
           }}
102 103
         >
103 104
           编辑
@@ -131,7 +132,7 @@ const RotationChartList = (props) => {
131 132
             key="2"
132 133
             type="primary"
133 134
             onClick={() => {
134
-              history.push('/rotationChart/add');
135
+              navigate('/cms/rotationChart/edit');
135 136
             }}
136 137
           >
137 138
             新增

+ 0
- 0
src/pages/sample/form/index.jsx Zobrazit soubor


Některé soubory nejsou zobrazny, neboť je v této revizi změněno mnoho souborů