From df1ce5a28b78db164b77c6516ed0cb3154958480 Mon Sep 17 00:00:00 2001 From: zhult13 Date: Sat, 17 Sep 2022 12:39:46 +0800 Subject: [PATCH 01/18] =?UTF-8?q?=E4=BF=AE=E5=A4=8Doidc-sso=E6=A0=B7?= =?UTF-8?q?=E4=BE=8B=E5=B7=A5=E7=A8=8B=E7=9A=84=E6=95=B0=E6=8D=AE=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- zlt-demo/sso-demo/oidc-sso/README.md | 1 + .../src/main/java/com/sso/demo/controller/ApiController.java | 5 ++++- zlt-demo/sso-demo/oidc-sso/src/main/resources/bootstrap.yml | 3 ++- zlt-doc/sql/oauth-center.sql | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/zlt-demo/sso-demo/oidc-sso/README.md b/zlt-demo/sso-demo/oidc-sso/README.md index 672698d8..11116508 100644 --- a/zlt-demo/sso-demo/oidc-sso/README.md +++ b/zlt-demo/sso-demo/oidc-sso/README.md @@ -11,6 +11,7 @@ alter table oauth_client_details add support_id_token tinyint(1) DEFAULT 1 COMME alter table oauth_client_details add id_token_validity int(11) DEFAULT 60 COMMENT 'id_token有效期'; update oauth_client_details set additional_information = '{"LOGOUT_NOTIFY_URL_LIST":"http://127.0.0.1:8082/logoutNotify"}' + , web_server_redirect_uri = 'http://127.0.0.1:8082/callback.html' where client_id = 'webApp'; ``` diff --git a/zlt-demo/sso-demo/oidc-sso/src/main/java/com/sso/demo/controller/ApiController.java b/zlt-demo/sso-demo/oidc-sso/src/main/java/com/sso/demo/controller/ApiController.java index 74103b05..72e3ff03 100644 --- a/zlt-demo/sso-demo/oidc-sso/src/main/java/com/sso/demo/controller/ApiController.java +++ b/zlt-demo/sso-demo/oidc-sso/src/main/java/com/sso/demo/controller/ApiController.java @@ -50,6 +50,9 @@ public class ApiController { @Value("${zlt.sso.redirect-uri:}") private String redirectUri; + @Value("${zlt.sso.scope:}") + private String scope; + @Value("${zlt.sso.access-token-uri:}") private String accessTokenUri; @@ -146,7 +149,7 @@ public Map getAccessToken(String code) { param.add("code", code); param.add("grant_type", "authorization_code"); param.add("redirect_uri", redirectUri); - param.add("scope", "all"); + param.add("scope", scope); param.add("nonce", this.genNonce()); HttpEntity> request = new HttpEntity<>(param, headers); ResponseEntity response = restTemplate.postForEntity(accessTokenUri, request , Map.class); diff --git a/zlt-demo/sso-demo/oidc-sso/src/main/resources/bootstrap.yml b/zlt-demo/sso-demo/oidc-sso/src/main/resources/bootstrap.yml index fc4c658e..bb422ead 100644 --- a/zlt-demo/sso-demo/oidc-sso/src/main/resources/bootstrap.yml +++ b/zlt-demo/sso-demo/oidc-sso/src/main/resources/bootstrap.yml @@ -11,4 +11,5 @@ zlt: client-secret: webApp redirect-uri: http://127.0.0.1:8082/callback.html access-token-uri: http://127.0.0.1:9900/api-uaa/oauth/token - jwt-key-uri: http://127.0.0.1:9900/api-uaa/tokens/key \ No newline at end of file + jwt-key-uri: http://127.0.0.1:9900/api-uaa/tokens/key + scope: app \ No newline at end of file diff --git a/zlt-doc/sql/oauth-center.sql b/zlt-doc/sql/oauth-center.sql index 6405352c..bdf168fc 100644 --- a/zlt-doc/sql/oauth-center.sql +++ b/zlt-doc/sql/oauth-center.sql @@ -30,6 +30,6 @@ CREATE TABLE `oauth_client_details` ( -- ---------------------------- -- Records of oauth_client_details -- ---------------------------- -INSERT INTO `oauth_client_details` VALUES (1, 'webApp', NULL, '$2a$10$06msMGYRH8nrm4iVnKFNKOoddB8wOwymVhbUzw/d3ZixD7Nq8ot72', 'webApp', 'app', 'authorization_code,password,refresh_token,client_credentials,implicit,password_code,openId,mobile_password', NULL, NULL, 3600, NULL, '{"LOGOUT_NOTIFY_URL_LIST":"http://127.0.0.1:8082/logoutNotify"}', 'true', NULL, NULL, 'pc端', 1, 60); +INSERT INTO `oauth_client_details` VALUES (1, 'webApp', NULL, '$2a$10$06msMGYRH8nrm4iVnKFNKOoddB8wOwymVhbUzw/d3ZixD7Nq8ot72', 'webApp', 'app', 'authorization_code,password,refresh_token,client_credentials,implicit,password_code,openId,mobile_password', 'http://127.0.0.1:8082/callback.html', NULL, 3600, NULL, '{"LOGOUT_NOTIFY_URL_LIST":"http://127.0.0.1:8082/logoutNotify"}', 'true', NULL, NULL, 'pc端', 1, 60); INSERT INTO `oauth_client_details` VALUES (2, 'app', NULL, '$2a$10$i3F515wEDiB4Gvj9ym9Prui0dasRttEUQ9ink4Wpgb4zEDCAlV8zO', 'app', 'app', 'authorization_code,password,refresh_token', 'http://127.0.0.1:8081/callback.html', NULL, 3600, NULL, '{"LOGOUT_NOTIFY_URL_LIST":"http://127.0.0.1:8081/logoutNotify"}', 'true', NULL, NULL, '移动端', 1, 60); INSERT INTO `oauth_client_details` VALUES (3, 'zlt', NULL, '$2a$10$/o.wuORzVcXaezmYVzwYMuoY7qeWXBALwQmkskXD/7C6rqfCyPrna', 'zlt', 'all', 'authorization_code,password,refresh_token,client_credentials', 'http://127.0.0.1:8080/singleLogin', NULL, 3600, 28800, '{}', 'true', '2018-12-27 00:50:30', '2018-12-27 00:50:30', '第三方应用', 1, 60); \ No newline at end of file From c16e8b365044fcc7d1f6b0e9058686fce2ca974f Mon Sep 17 00:00:00 2001 From: Gao Shan Date: Tue, 4 Oct 2022 00:07:31 +0800 Subject: [PATCH 02/18] beta --- zlt-web/src/main/java/com/central/ui/UiBootApplication.java | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 zlt-web/src/main/java/com/central/ui/UiBootApplication.java diff --git a/zlt-web/src/main/java/com/central/ui/UiBootApplication.java b/zlt-web/src/main/java/com/central/ui/UiBootApplication.java new file mode 100644 index 00000000..0d8524b8 --- /dev/null +++ b/zlt-web/src/main/java/com/central/ui/UiBootApplication.java @@ -0,0 +1,2 @@ +package com.central.ui;public class UiBootApplication { +} From 81d68e3aea2171bcb665ad6a1bddeb020ba62dfb Mon Sep 17 00:00:00 2001 From: Gao Shan Date: Tue, 4 Oct 2022 00:12:49 +0800 Subject: [PATCH 03/18] beta-0.1 --- zlt-web/.editorconfig | 16 + zlt-web/.eslintignore | 8 + zlt-web/.eslintrc.js | 8 + zlt-web/.gitignore | 41 ++ zlt-web/.prettierignore | 23 + zlt-web/.prettierrc.js | 5 + zlt-web/.stylelintrc.js | 3 + zlt-web/.vscode/extensions.json | 8 + zlt-web/.vscode/settings.json | 5 + zlt-web/README.md | 57 ++ zlt-web/config/config.dev.ts | 15 + zlt-web/config/config.ts | 76 +++ zlt-web/config/defaultSettings.ts | 21 + zlt-web/config/oneapi.json | 593 ++++++++++++++++++ zlt-web/config/proxy.ts | 54 ++ zlt-web/config/routes.ts | 109 ++++ zlt-web/jest.config.js | 9 + zlt-web/jsconfig.json | 11 + zlt-web/mock/listTableList.ts | 174 +++++ zlt-web/mock/notices.ts | 107 ++++ zlt-web/mock/route.ts | 5 + zlt-web/mock/user.ts | 203 ++++++ zlt-web/package.json | 107 ++++ zlt-web/playwright.config.ts | 22 + zlt-web/pom.xml | 135 +++- zlt-web/public/CNAME | 1 + zlt-web/public/campaign.svg | 1 + zlt-web/public/favicon.ico | Bin 0 -> 4286 bytes zlt-web/public/icons/icon-128x128.png | Bin 0 -> 1931 bytes zlt-web/public/icons/icon-192x192.png | Bin 0 -> 3161 bytes zlt-web/public/icons/icon-512x512.png | Bin 0 -> 14340 bytes zlt-web/public/logo.png | Bin 0 -> 3665 bytes zlt-web/public/logo.svg | 1 + zlt-web/public/pro_icon.svg | 5 + zlt-web/src/access.ts | 9 + zlt-web/src/app.tsx | 302 +++++++++ zlt-web/src/components/Footer/index.tsx | 35 ++ .../src/components/HeaderDropdown/index.less | 16 + .../src/components/HeaderDropdown/index.tsx | 17 + .../src/components/HeaderSearch/index.less | 25 + zlt-web/src/components/HeaderSearch/index.tsx | 101 +++ .../src/components/NoticeIcon/NoticeIcon.tsx | 126 ++++ .../src/components/NoticeIcon/NoticeList.less | 103 +++ .../src/components/NoticeIcon/NoticeList.tsx | 112 ++++ zlt-web/src/components/NoticeIcon/index.less | 35 ++ zlt-web/src/components/NoticeIcon/index.tsx | 152 +++++ .../RightContent/AvatarDropdown.tsx | 113 ++++ .../src/components/RightContent/index.less | 84 +++ zlt-web/src/components/RightContent/index.tsx | 69 ++ zlt-web/src/components/index.md | 271 ++++++++ zlt-web/src/e2e/baseLayout.e2e.spec.ts | 45 ++ zlt-web/src/global.less | 72 +++ zlt-web/src/global.tsx | 91 +++ zlt-web/src/locales/zh-CN.ts | 25 + zlt-web/src/locales/zh-CN/component.ts | 5 + zlt-web/src/locales/zh-CN/globalHeader.ts | 17 + zlt-web/src/locales/zh-CN/menu.ts | 52 ++ zlt-web/src/locales/zh-CN/pages.ts | 65 ++ zlt-web/src/locales/zh-CN/pwa.ts | 6 + zlt-web/src/locales/zh-CN/settingDrawer.ts | 31 + zlt-web/src/locales/zh-CN/settings.ts | 55 ++ .../com/central/ui/UiBootApplication.java | 13 +- zlt-web/src/manifest.json | 22 + zlt-web/src/pages/404.tsx | 18 + zlt-web/src/pages/Admin.tsx | 45 ++ zlt-web/src/pages/Welcome.less | 14 + zlt-web/src/pages/Welcome.tsx | 223 +++++++ zlt-web/src/pages/document.ejs | 226 +++++++ zlt-web/src/pages/log/AuditLog/index.less | 1 + zlt-web/src/pages/log/AuditLog/index.tsx | 130 ++++ zlt-web/src/pages/log/SlowSqlLog/index.less | 1 + zlt-web/src/pages/log/SlowSqlLog/index.tsx | 112 ++++ .../pages/log/SysLog/components/TraceView.tsx | 76 +++ zlt-web/src/pages/log/SysLog/index.less | 12 + zlt-web/src/pages/log/SysLog/index.tsx | 158 +++++ .../search/Index/components/IndexView.tsx | 57 ++ zlt-web/src/pages/search/Index/index.less | 12 + zlt-web/src/pages/search/Index/index.tsx | 191 ++++++ zlt-web/src/pages/search/User/index.less | 1 + zlt-web/src/pages/search/User/index.tsx | 88 +++ zlt-web/src/pages/system/App/index.less | 1 + zlt-web/src/pages/system/App/index.tsx | 109 ++++ zlt-web/src/pages/system/Generator/index.less | 1 + zlt-web/src/pages/system/Generator/index.tsx | 77 +++ zlt-web/src/pages/system/Menu/index.less | 1 + zlt-web/src/pages/system/Menu/index.tsx | 144 +++++ .../system/Role/components/AssignAuth.tsx | 65 ++ .../system/Role/components/UpdateForm.tsx | 70 +++ zlt-web/src/pages/system/Role/index.less | 1 + zlt-web/src/pages/system/Role/index.tsx | 191 ++++++ zlt-web/src/pages/system/Token/index.less | 1 + zlt-web/src/pages/system/Token/index.tsx | 94 +++ .../system/User/components/UpdateForm.tsx | 116 ++++ zlt-web/src/pages/system/User/index.less | 1 + zlt-web/src/pages/system/User/index.tsx | 247 ++++++++ zlt-web/src/pages/system/UserInfo/index.less | 42 ++ zlt-web/src/pages/system/UserInfo/index.tsx | 93 +++ zlt-web/src/pages/user/Login/index.less | 50 ++ zlt-web/src/pages/user/Login/index.tsx | 174 +++++ zlt-web/src/service-worker.js | 65 ++ zlt-web/src/services/ant-design-pro/api.ts | 46 ++ zlt-web/src/services/ant-design-pro/index.ts | 8 + .../src/services/ant-design-pro/typings.d.ts | 59 ++ zlt-web/src/services/search/api.ts | 56 ++ zlt-web/src/services/search/index.ts | 8 + zlt-web/src/services/search/typings.d.ts | 50 ++ zlt-web/src/services/swagger/index.ts | 12 + zlt-web/src/services/swagger/pet.ts | 166 +++++ zlt-web/src/services/swagger/store.ts | 54 ++ zlt-web/src/services/swagger/typings.d.ts | 52 ++ zlt-web/src/services/swagger/user.ts | 114 ++++ zlt-web/src/services/system/api.ts | 100 +++ zlt-web/src/services/system/index.ts | 8 + zlt-web/src/services/system/typings.d.ts | 84 +++ zlt-web/src/services/welcome/api.ts | 9 + zlt-web/src/services/welcome/index.ts | 8 + zlt-web/src/services/welcome/typings.d.ts | 34 + zlt-web/src/typings.d.ts | 25 + zlt-web/src/util/download.ts | 26 + zlt-web/src/util/treeify.tsx | 45 ++ zlt-web/tests/run-tests.js | 47 ++ zlt-web/tests/setupTests.js | 10 + zlt-web/tsconfig.json | 42 ++ 123 files changed, 7845 insertions(+), 18 deletions(-) create mode 100644 zlt-web/.editorconfig create mode 100644 zlt-web/.eslintignore create mode 100644 zlt-web/.eslintrc.js create mode 100644 zlt-web/.gitignore create mode 100644 zlt-web/.prettierignore create mode 100644 zlt-web/.prettierrc.js create mode 100644 zlt-web/.stylelintrc.js create mode 100644 zlt-web/.vscode/extensions.json create mode 100644 zlt-web/.vscode/settings.json create mode 100644 zlt-web/README.md create mode 100644 zlt-web/config/config.dev.ts create mode 100644 zlt-web/config/config.ts create mode 100644 zlt-web/config/defaultSettings.ts create mode 100644 zlt-web/config/oneapi.json create mode 100644 zlt-web/config/proxy.ts create mode 100644 zlt-web/config/routes.ts create mode 100644 zlt-web/jest.config.js create mode 100644 zlt-web/jsconfig.json create mode 100644 zlt-web/mock/listTableList.ts create mode 100644 zlt-web/mock/notices.ts create mode 100644 zlt-web/mock/route.ts create mode 100644 zlt-web/mock/user.ts create mode 100644 zlt-web/package.json create mode 100644 zlt-web/playwright.config.ts create mode 100644 zlt-web/public/CNAME create mode 100644 zlt-web/public/campaign.svg create mode 100644 zlt-web/public/favicon.ico create mode 100644 zlt-web/public/icons/icon-128x128.png create mode 100644 zlt-web/public/icons/icon-192x192.png create mode 100644 zlt-web/public/icons/icon-512x512.png create mode 100644 zlt-web/public/logo.png create mode 100644 zlt-web/public/logo.svg create mode 100644 zlt-web/public/pro_icon.svg create mode 100644 zlt-web/src/access.ts create mode 100644 zlt-web/src/app.tsx create mode 100644 zlt-web/src/components/Footer/index.tsx create mode 100644 zlt-web/src/components/HeaderDropdown/index.less create mode 100644 zlt-web/src/components/HeaderDropdown/index.tsx create mode 100644 zlt-web/src/components/HeaderSearch/index.less create mode 100644 zlt-web/src/components/HeaderSearch/index.tsx create mode 100644 zlt-web/src/components/NoticeIcon/NoticeIcon.tsx create mode 100644 zlt-web/src/components/NoticeIcon/NoticeList.less create mode 100644 zlt-web/src/components/NoticeIcon/NoticeList.tsx create mode 100644 zlt-web/src/components/NoticeIcon/index.less create mode 100644 zlt-web/src/components/NoticeIcon/index.tsx create mode 100644 zlt-web/src/components/RightContent/AvatarDropdown.tsx create mode 100644 zlt-web/src/components/RightContent/index.less create mode 100644 zlt-web/src/components/RightContent/index.tsx create mode 100644 zlt-web/src/components/index.md create mode 100644 zlt-web/src/e2e/baseLayout.e2e.spec.ts create mode 100644 zlt-web/src/global.less create mode 100644 zlt-web/src/global.tsx create mode 100644 zlt-web/src/locales/zh-CN.ts create mode 100644 zlt-web/src/locales/zh-CN/component.ts create mode 100644 zlt-web/src/locales/zh-CN/globalHeader.ts create mode 100644 zlt-web/src/locales/zh-CN/menu.ts create mode 100644 zlt-web/src/locales/zh-CN/pages.ts create mode 100644 zlt-web/src/locales/zh-CN/pwa.ts create mode 100644 zlt-web/src/locales/zh-CN/settingDrawer.ts create mode 100644 zlt-web/src/locales/zh-CN/settings.ts create mode 100644 zlt-web/src/manifest.json create mode 100644 zlt-web/src/pages/404.tsx create mode 100644 zlt-web/src/pages/Admin.tsx create mode 100644 zlt-web/src/pages/Welcome.less create mode 100644 zlt-web/src/pages/Welcome.tsx create mode 100644 zlt-web/src/pages/document.ejs create mode 100644 zlt-web/src/pages/log/AuditLog/index.less create mode 100644 zlt-web/src/pages/log/AuditLog/index.tsx create mode 100644 zlt-web/src/pages/log/SlowSqlLog/index.less create mode 100644 zlt-web/src/pages/log/SlowSqlLog/index.tsx create mode 100644 zlt-web/src/pages/log/SysLog/components/TraceView.tsx create mode 100644 zlt-web/src/pages/log/SysLog/index.less create mode 100644 zlt-web/src/pages/log/SysLog/index.tsx create mode 100644 zlt-web/src/pages/search/Index/components/IndexView.tsx create mode 100644 zlt-web/src/pages/search/Index/index.less create mode 100644 zlt-web/src/pages/search/Index/index.tsx create mode 100644 zlt-web/src/pages/search/User/index.less create mode 100644 zlt-web/src/pages/search/User/index.tsx create mode 100644 zlt-web/src/pages/system/App/index.less create mode 100644 zlt-web/src/pages/system/App/index.tsx create mode 100644 zlt-web/src/pages/system/Generator/index.less create mode 100644 zlt-web/src/pages/system/Generator/index.tsx create mode 100644 zlt-web/src/pages/system/Menu/index.less create mode 100644 zlt-web/src/pages/system/Menu/index.tsx create mode 100644 zlt-web/src/pages/system/Role/components/AssignAuth.tsx create mode 100644 zlt-web/src/pages/system/Role/components/UpdateForm.tsx create mode 100644 zlt-web/src/pages/system/Role/index.less create mode 100644 zlt-web/src/pages/system/Role/index.tsx create mode 100644 zlt-web/src/pages/system/Token/index.less create mode 100644 zlt-web/src/pages/system/Token/index.tsx create mode 100644 zlt-web/src/pages/system/User/components/UpdateForm.tsx create mode 100644 zlt-web/src/pages/system/User/index.less create mode 100644 zlt-web/src/pages/system/User/index.tsx create mode 100644 zlt-web/src/pages/system/UserInfo/index.less create mode 100644 zlt-web/src/pages/system/UserInfo/index.tsx create mode 100644 zlt-web/src/pages/user/Login/index.less create mode 100644 zlt-web/src/pages/user/Login/index.tsx create mode 100644 zlt-web/src/service-worker.js create mode 100644 zlt-web/src/services/ant-design-pro/api.ts create mode 100644 zlt-web/src/services/ant-design-pro/index.ts create mode 100644 zlt-web/src/services/ant-design-pro/typings.d.ts create mode 100644 zlt-web/src/services/search/api.ts create mode 100644 zlt-web/src/services/search/index.ts create mode 100644 zlt-web/src/services/search/typings.d.ts create mode 100644 zlt-web/src/services/swagger/index.ts create mode 100644 zlt-web/src/services/swagger/pet.ts create mode 100644 zlt-web/src/services/swagger/store.ts create mode 100644 zlt-web/src/services/swagger/typings.d.ts create mode 100644 zlt-web/src/services/swagger/user.ts create mode 100644 zlt-web/src/services/system/api.ts create mode 100644 zlt-web/src/services/system/index.ts create mode 100644 zlt-web/src/services/system/typings.d.ts create mode 100644 zlt-web/src/services/welcome/api.ts create mode 100644 zlt-web/src/services/welcome/index.ts create mode 100644 zlt-web/src/services/welcome/typings.d.ts create mode 100644 zlt-web/src/typings.d.ts create mode 100644 zlt-web/src/util/download.ts create mode 100644 zlt-web/src/util/treeify.tsx create mode 100644 zlt-web/tests/run-tests.js create mode 100644 zlt-web/tests/setupTests.js create mode 100644 zlt-web/tsconfig.json diff --git a/zlt-web/.editorconfig b/zlt-web/.editorconfig new file mode 100644 index 00000000..7e3649ac --- /dev/null +++ b/zlt-web/.editorconfig @@ -0,0 +1,16 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/zlt-web/.eslintignore b/zlt-web/.eslintignore new file mode 100644 index 00000000..8336e935 --- /dev/null +++ b/zlt-web/.eslintignore @@ -0,0 +1,8 @@ +/lambda/ +/scripts +/config +.history +public +dist +.umi +mock \ No newline at end of file diff --git a/zlt-web/.eslintrc.js b/zlt-web/.eslintrc.js new file mode 100644 index 00000000..b882c20e --- /dev/null +++ b/zlt-web/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + extends: [require.resolve('@umijs/fabric/dist/eslint')], + globals: { + ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true, + page: true, + REACT_APP_ENV: true, + }, +}; diff --git a/zlt-web/.gitignore b/zlt-web/.gitignore new file mode 100644 index 00000000..0c85e259 --- /dev/null +++ b/zlt-web/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +**/node_modules +# roadhog-api-doc ignore +/src/utils/request-temp.js +_roadhog-api-doc + +# production +/dist +/node + +# misc +.DS_Store +npm-debug.log* +yarn-error.log + +/coverage +.idea +yarn.lock +package-lock.json +pnpm-lock.yaml +*bak + + +# visual studio code +.history +*.log +functions/* +.temp/** + +# umi +.umi +.umi-production + +# screenshot +screenshot +.firebase +.eslintcache + +build diff --git a/zlt-web/.prettierignore b/zlt-web/.prettierignore new file mode 100644 index 00000000..d17efb44 --- /dev/null +++ b/zlt-web/.prettierignore @@ -0,0 +1,23 @@ +**/*.svg +package.json +.umi +.umi-production +/dist +.dockerignore +.DS_Store +.eslintignore +*.png +*.toml +docker +.editorconfig +Dockerfile* +.gitignore +.prettierignore +LICENSE +.eslintcache +*.lock +yarn-error.log +.history +CNAME +/build +/public \ No newline at end of file diff --git a/zlt-web/.prettierrc.js b/zlt-web/.prettierrc.js new file mode 100644 index 00000000..7b597d78 --- /dev/null +++ b/zlt-web/.prettierrc.js @@ -0,0 +1,5 @@ +const fabric = require('@umijs/fabric'); + +module.exports = { + ...fabric.prettier, +}; diff --git a/zlt-web/.stylelintrc.js b/zlt-web/.stylelintrc.js new file mode 100644 index 00000000..a1184de4 --- /dev/null +++ b/zlt-web/.stylelintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@umijs/fabric/dist/stylelint')], +}; diff --git a/zlt-web/.vscode/extensions.json b/zlt-web/.vscode/extensions.json new file mode 100644 index 00000000..33f300da --- /dev/null +++ b/zlt-web/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "stylelint.vscode-stylelint", + "wangzy.sneak-mark" + ] +} diff --git a/zlt-web/.vscode/settings.json b/zlt-web/.vscode/settings.json new file mode 100644 index 00000000..a5d9d035 --- /dev/null +++ b/zlt-web/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.formatOnSave": true, + "prettier.requireConfig": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" +} diff --git a/zlt-web/README.md b/zlt-web/README.md new file mode 100644 index 00000000..4c89a727 --- /dev/null +++ b/zlt-web/README.md @@ -0,0 +1,57 @@ +# Ant Design Pro + +This project is initialized with [Ant Design Pro](https://pro.ant.design). Follow is the quick guide for how to use. + +## Environment Prepare + +Install `node_modules`: + +```bash +npm install +``` + +or + +```bash +yarn +``` + +## Provided Scripts + +Ant Design Pro provides some useful script to help you quick start and build with web project, code style check and test. + +Scripts provided in `package.json`. It's safe to modify or add additional script: + +### Start project + +```bash +npm start +``` + +### Build project + +```bash +npm run build +``` + +### Check code style + +```bash +npm run lint +``` + +You can also use script to auto fix some lint error: + +```bash +npm run lint:fix +``` + +### Test code + +```bash +npm test +``` + +## More + +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). diff --git a/zlt-web/config/config.dev.ts b/zlt-web/config/config.dev.ts new file mode 100644 index 00000000..ab0e590f --- /dev/null +++ b/zlt-web/config/config.dev.ts @@ -0,0 +1,15 @@ +// https://umijs.org/config/ +import { defineConfig } from 'umi'; + +export default defineConfig({ + plugins: [ + // https://github.com/zthxxx/react-dev-inspector + 'react-dev-inspector/plugins/umi/react-inspector', + ], + // https://github.com/zthxxx/react-dev-inspector#inspector-loader-props + inspectorConfig: { + exclude: [], + babelPlugins: [], + babelOptions: {}, + }, +}); diff --git a/zlt-web/config/config.ts b/zlt-web/config/config.ts new file mode 100644 index 00000000..fced298f --- /dev/null +++ b/zlt-web/config/config.ts @@ -0,0 +1,76 @@ +// https://umijs.org/config/ +import { defineConfig } from 'umi'; +import { join } from 'path'; + +import defaultSettings from './defaultSettings'; +import proxy from './proxy'; +import routes from './routes'; + +const { REACT_APP_ENV } = process.env; + +export default defineConfig({ + hash: true, + antd: {}, + dva: { + hmr: true, + }, + layout: { + // https://umijs.org/zh-CN/plugins/plugin-layout + locale: false, + siderWidth: 208, + ...defaultSettings, + }, + // https://umijs.org/zh-CN/plugins/plugin-locale + locale: { + // default zh-CN + default: 'zh-CN', + antd: true, + // default true, when it is true, will use `navigator.language` overwrite default + baseNavigator: true, + }, + dynamicImport: { + loading: '@ant-design/pro-layout/es/PageLoading', + }, + targets: { + ie: 11, + }, + // umi routes: https://umijs.org/docs/routing + routes, + access: {}, + // Theme for antd: https://ant.design/docs/react/customize-theme-cn + theme: { + // 如果不想要 configProvide 动态设置主题需要把这个设置为 default + // 只有设置为 variable, 才能使用 configProvide 动态设置主色调 + // https://ant.design/docs/react/customize-theme-variable-cn + 'root-entry-name': 'variable', + }, + // esbuild is father build tools + // https://umijs.org/plugins/plugin-esbuild + esbuild: {}, + title: false, + ignoreMomentLocale: true, + proxy: proxy[REACT_APP_ENV || 'dev'], + manifest: { + basePath: '/', + }, + // Fast Refresh 热更新 + fastRefresh: {}, + openAPI: [ + { + requestLibPath: "import { request } from 'umi'", + // 或者使用在线的版本 + // schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json" + schemaPath: join(__dirname, 'oneapi.json'), + mock: false, + }, + { + requestLibPath: "import { request } from 'umi'", + schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json', + projectName: 'swagger', + }, + ], + nodeModulesTransform: { type: 'none' }, + mfsu: {}, + webpack5: {}, + exportStatic: {}, +}); diff --git a/zlt-web/config/defaultSettings.ts b/zlt-web/config/defaultSettings.ts new file mode 100644 index 00000000..7700cad0 --- /dev/null +++ b/zlt-web/config/defaultSettings.ts @@ -0,0 +1,21 @@ +import { Settings as LayoutSettings } from '@ant-design/pro-components'; + +const Settings: LayoutSettings & { + pwa?: boolean; + logo?: string; +} = { + navTheme: 'dark', + // 拂晓蓝 + primaryColor: '#1890ff', + layout: 'mix', + contentWidth: 'Fluid', + fixedHeader: false, + fixSiderbar: true, + colorWeak: false, + title: 'Microservices-Platform', + pwa: false, + logo: '/logo.png', + iconfontUrl: '', +}; + +export default Settings; diff --git a/zlt-web/config/oneapi.json b/zlt-web/config/oneapi.json new file mode 100644 index 00000000..c77d988b --- /dev/null +++ b/zlt-web/config/oneapi.json @@ -0,0 +1,593 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Ant Design Pro", + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:8000/" + }, + { + "url": "https://localhost:8000/" + } + ], + "paths": { + "/api/currentUser": { + "get": { + "tags": ["api"], + "description": "获取当前的用户", + "operationId": "currentUser", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CurrentUser" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "x-swagger-router-controller": "api" + }, + "/api/login/captcha": { + "post": { + "description": "发送验证码", + "operationId": "getFakeCaptcha", + "tags": ["login"], + "parameters": [ + { + "name": "phone", + "in": "query", + "description": "手机号", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FakeCaptcha" + } + } + } + } + } + } + }, + "/api/login/outLogin": { + "post": { + "description": "登录接口", + "operationId": "outLogin", + "tags": ["login"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "x-swagger-router-controller": "api" + }, + "/api/login/account": { + "post": { + "tags": ["login"], + "description": "登录接口", + "operationId": "login", + "requestBody": { + "description": "登录系统", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginParams" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginResult" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "x-swagger-router-controller": "api" + }, + "/api/notices": { + "summary": "getNotices", + "description": "NoticeIconItem", + "get": { + "tags": ["api"], + "operationId": "getNotices", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NoticeIconList" + } + } + } + } + } + } + }, + "/api/rule": { + "get": { + "tags": ["rule"], + "description": "获取规则列表", + "operationId": "rule", + "parameters": [ + { + "name": "current", + "in": "query", + "description": "当前的页码", + "schema": { + "type": "number" + } + }, + { + "name": "pageSize", + "in": "query", + "description": "页面的容量", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleList" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "post": { + "tags": ["rule"], + "description": "新建规则", + "operationId": "addRule", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleListItem" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "put": { + "tags": ["rule"], + "description": "新建规则", + "operationId": "updateRule", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleListItem" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "delete": { + "tags": ["rule"], + "description": "删除规则", + "operationId": "removeRule", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "x-swagger-router-controller": "api" + }, + "/swagger": { + "x-swagger-pipe": "swagger_raw" + } + }, + "components": { + "schemas": { + "CurrentUser": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "userid": { + "type": "string" + }, + "email": { + "type": "string" + }, + "signature": { + "type": "string" + }, + "title": { + "type": "string" + }, + "group": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "label": { + "type": "string" + } + } + } + }, + "notifyCount": { + "type": "integer", + "format": "int32" + }, + "unreadCount": { + "type": "integer", + "format": "int32" + }, + "country": { + "type": "string" + }, + "access": { + "type": "string" + }, + "geographic": { + "type": "object", + "properties": { + "province": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "key": { + "type": "string" + } + } + }, + "city": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "key": { + "type": "string" + } + } + } + } + }, + "address": { + "type": "string" + }, + "phone": { + "type": "string" + } + } + }, + "LoginResult": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "currentAuthority": { + "type": "string" + } + } + }, + "PageParams": { + "type": "object", + "properties": { + "current": { + "type": "number" + }, + "pageSize": { + "type": "number" + } + } + }, + "RuleListItem": { + "type": "object", + "properties": { + "key": { + "type": "integer", + "format": "int32" + }, + "disabled": { + "type": "boolean" + }, + "href": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "desc": { + "type": "string" + }, + "callNo": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "integer", + "format": "int32" + }, + "updatedAt": { + "type": "string", + "format": "datetime" + }, + "createdAt": { + "type": "string", + "format": "datetime" + }, + "progress": { + "type": "integer", + "format": "int32" + } + } + }, + "RuleList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RuleListItem" + } + }, + "total": { + "type": "integer", + "description": "列表的内容总数", + "format": "int32" + }, + "success": { + "type": "boolean" + } + } + }, + "FakeCaptcha": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string" + } + } + }, + "LoginParams": { + "type": "object", + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "autoLogin": { + "type": "boolean" + }, + "type": { + "type": "string" + } + } + }, + "ErrorResponse": { + "required": ["errorCode"], + "type": "object", + "properties": { + "errorCode": { + "type": "string", + "description": "业务约定的错误码" + }, + "errorMessage": { + "type": "string", + "description": "业务上的错误信息" + }, + "success": { + "type": "boolean", + "description": "业务上的请求是否成功" + } + } + }, + "NoticeIconList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NoticeIconItem" + } + }, + "total": { + "type": "integer", + "description": "列表的内容总数", + "format": "int32" + }, + "success": { + "type": "boolean" + } + } + }, + "NoticeIconItemType": { + "title": "NoticeIconItemType", + "description": "已读未读列表的枚举", + "type": "string", + "properties": {}, + "enum": ["notification", "message", "event"] + }, + "NoticeIconItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "extra": { + "type": "string", + "format": "any" + }, + "key": { "type": "string" }, + "read": { + "type": "boolean" + }, + "avatar": { + "type": "string" + }, + "title": { + "type": "string" + }, + "status": { + "type": "string" + }, + "datetime": { + "type": "string", + "format": "date" + }, + "description": { + "type": "string" + }, + "type": { + "extensions": { + "x-is-enum": true + }, + "$ref": "#/components/schemas/NoticeIconItemType" + } + } + } + } + } +} diff --git a/zlt-web/config/proxy.ts b/zlt-web/config/proxy.ts new file mode 100644 index 00000000..e44df51a --- /dev/null +++ b/zlt-web/config/proxy.ts @@ -0,0 +1,54 @@ +/** + * 在生产环境 代理是无法生效的,所以这里没有生产环境的配置 + * ------------------------------- + * The agent cannot take effect in the production environment + * so there is no configuration of the production environment + * For details, please see + * https://pro.ant.design/docs/deploy + */ +export default { + dev: { + // localhost:8000/api/** -> https://preview.pro.ant.design/api/** + '/api/': { + // 要代理的地址 + target: 'https://preview.pro.ant.design', + // 配置了这个可以从 http 代理到 https + // 依赖 origin 的功能可能需要这个,比如 cookie + changeOrigin: true, + }, + '/api-uaa/': { + target: 'http://gateway.zlt2000.cn', + changeOrigin: true, + }, + '/api-user/': { + target: 'http://gateway.zlt2000.cn', + changeOrigin: true, + }, + '/api-log/': { + target: 'http://gateway.zlt2000.cn', + changeOrigin: true, + }, + '/api-search/': { + target: 'http://gateway.zlt2000.cn', + changeOrigin: true, + }, + '/api-generator/': { + target: 'http://gateway.zlt2000.cn', + changeOrigin: true, + }, + }, + test: { + '/api/': { + target: 'https://proapi.azurewebsites.net', + changeOrigin: true, + pathRewrite: { '^': '' }, + }, + }, + pre: { + '/api/': { + target: 'your pre url', + changeOrigin: true, + pathRewrite: { '^': '' }, + }, + }, +}; diff --git a/zlt-web/config/routes.ts b/zlt-web/config/routes.ts new file mode 100644 index 00000000..c5ea20fe --- /dev/null +++ b/zlt-web/config/routes.ts @@ -0,0 +1,109 @@ +export default [ + { + path: '/user', + layout: false, + routes: [ + { + name: 'login', + path: '/user/login', + component: './user/Login', + }, + { + component: './404', + }, + ], + }, + { + path: '/system', + routes: [ + { + path: '/system/user.html', + component: './system/User', + }, + { + path: '/system/role.html', + component: './system/Role', + }, + { + path: '/system/tokens.html', + component: './system/Token', + }, + { + path: '/system/menus.html', + component: './system/Menu', + }, + { + path: '/system/myInfo.html', + component: './system/UserInfo', + }, + ], + }, + { + path: '/search', + routes: [ + { + path: '/search/index_manager.html', + component: './search/Index', + }, + { + path: '/search/user_search.html', + component: './search/User', + }, + ], + }, + { + path: '/log', + routes: [ + { + path: '/log/sysLog.html', + component: './log/SysLog', + }, + { + path: '/log/auditLog.html', + component: './log/AuditLog', + }, + { + path: '/log/slowQueryLog.html', + component: './log/SlowSqlLog', + }, + ], + }, + { + path: '/attestation/app.html', + component: './system/App', + }, + { + path: '/generator/list.html', + component: './system/Generator', + }, + { + path: '/welcome', + name: 'welcome', + icon: 'smile', + component: './Welcome', + }, + { + path: '/admin', + name: 'admin', + icon: 'crown', + access: 'canAdmin', + routes: [ + { + path: '/admin/sub-page', + name: 'sub-page', + icon: 'smile', + component: './Welcome', + }, + { + component: './404', + }, + ], + }, + { + path: '/', + redirect: '/welcome', + }, + { + component: './404', + }, +]; diff --git a/zlt-web/jest.config.js b/zlt-web/jest.config.js new file mode 100644 index 00000000..47295738 --- /dev/null +++ b/zlt-web/jest.config.js @@ -0,0 +1,9 @@ +module.exports = { + testURL: 'http://localhost:8000', + verbose: false, + extraSetupFiles: ['./tests/setupTests.js'], + globals: { + ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: false, + localStorage: null, + }, +}; diff --git a/zlt-web/jsconfig.json b/zlt-web/jsconfig.json new file mode 100644 index 00000000..197bee5d --- /dev/null +++ b/zlt-web/jsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/zlt-web/mock/listTableList.ts b/zlt-web/mock/listTableList.ts new file mode 100644 index 00000000..08ed86de --- /dev/null +++ b/zlt-web/mock/listTableList.ts @@ -0,0 +1,174 @@ +import { Request, Response } from 'express'; +import moment from 'moment'; +import { parse } from 'url'; + +// mock tableListDataSource +const genList = (current: number, pageSize: number) => { + const tableListDataSource: API.RuleListItem[] = []; + + for (let i = 0; i < pageSize; i += 1) { + const index = (current - 1) * 10 + i; + tableListDataSource.push({ + key: index, + disabled: i % 6 === 0, + href: 'https://ant.design', + avatar: [ + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + ][i % 2], + name: `TradeCode ${index}`, + owner: '曲丽丽', + desc: '这是一段描述', + callNo: Math.floor(Math.random() * 1000), + status: Math.floor(Math.random() * 10) % 4, + updatedAt: moment().format('YYYY-MM-DD'), + createdAt: moment().format('YYYY-MM-DD'), + progress: Math.ceil(Math.random() * 100), + }); + } + tableListDataSource.reverse(); + return tableListDataSource; +}; + +let tableListDataSource = genList(1, 100); + +function getRule(req: Request, res: Response, u: string) { + let realUrl = u; + if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') { + realUrl = req.url; + } + const { current = 1, pageSize = 10 } = req.query; + const params = parse(realUrl, true).query as unknown as API.PageParams & + API.RuleListItem & { + sorter: any; + filter: any; + }; + + let dataSource = [...tableListDataSource].slice( + ((current as number) - 1) * (pageSize as number), + (current as number) * (pageSize as number), + ); + if (params.sorter) { + const sorter = JSON.parse(params.sorter); + dataSource = dataSource.sort((prev, next) => { + let sortNumber = 0; + Object.keys(sorter).forEach((key) => { + if (sorter[key] === 'descend') { + if (prev[key] - next[key] > 0) { + sortNumber += -1; + } else { + sortNumber += 1; + } + return; + } + if (prev[key] - next[key] > 0) { + sortNumber += 1; + } else { + sortNumber += -1; + } + }); + return sortNumber; + }); + } + if (params.filter) { + const filter = JSON.parse(params.filter as any) as { + [key: string]: string[]; + }; + if (Object.keys(filter).length > 0) { + dataSource = dataSource.filter((item) => { + return Object.keys(filter).some((key) => { + if (!filter[key]) { + return true; + } + if (filter[key].includes(`${item[key]}`)) { + return true; + } + return false; + }); + }); + } + } + + if (params.name) { + dataSource = dataSource.filter((data) => data?.name?.includes(params.name || '')); + } + const result = { + data: dataSource, + total: tableListDataSource.length, + success: true, + pageSize, + current: parseInt(`${params.current}`, 10) || 1, + }; + + return res.json(result); +} + +function postRule(req: Request, res: Response, u: string, b: Request) { + let realUrl = u; + if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') { + realUrl = req.url; + } + + const body = (b && b.body) || req.body; + const { method, name, desc, key } = body; + + switch (method) { + /* eslint no-case-declarations:0 */ + case 'delete': + tableListDataSource = tableListDataSource.filter((item) => key.indexOf(item.key) === -1); + break; + case 'post': + (() => { + const i = Math.ceil(Math.random() * 10000); + const newRule: API.RuleListItem = { + key: tableListDataSource.length, + href: 'https://ant.design', + avatar: [ + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + ][i % 2], + name, + owner: '曲丽丽', + desc, + callNo: Math.floor(Math.random() * 1000), + status: Math.floor(Math.random() * 10) % 2, + updatedAt: moment().format('YYYY-MM-DD'), + createdAt: moment().format('YYYY-MM-DD'), + progress: Math.ceil(Math.random() * 100), + }; + tableListDataSource.unshift(newRule); + return res.json(newRule); + })(); + return; + + case 'update': + (() => { + let newRule = {}; + tableListDataSource = tableListDataSource.map((item) => { + if (item.key === key) { + newRule = { ...item, desc, name }; + return { ...item, desc, name }; + } + return item; + }); + return res.json(newRule); + })(); + return; + default: + break; + } + + const result = { + list: tableListDataSource, + pagination: { + total: tableListDataSource.length, + }, + }; + + res.json(result); +} + +export default { + 'GET /api/rule': getRule, + 'POST /api/rule': postRule, +}; diff --git a/zlt-web/mock/notices.ts b/zlt-web/mock/notices.ts new file mode 100644 index 00000000..732dd584 --- /dev/null +++ b/zlt-web/mock/notices.ts @@ -0,0 +1,107 @@ +import { Request, Response } from 'express'; + +const getNotices = (req: Request, res: Response) => { + res.json({ + data: [ + { + id: '000000001', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', + title: '你收到了 14 份新周报', + datetime: '2017-08-09', + type: 'notification', + }, + { + id: '000000002', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png', + title: '你推荐的 曲妮妮 已通过第三轮面试', + datetime: '2017-08-08', + type: 'notification', + }, + { + id: '000000003', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png', + title: '这种模板可以区分多种通知类型', + datetime: '2017-08-07', + read: true, + type: 'notification', + }, + { + id: '000000004', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + datetime: '2017-08-07', + type: 'notification', + }, + { + id: '000000005', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', + title: '内容不要超过两行字,超出时自动截断', + datetime: '2017-08-07', + type: 'notification', + }, + { + id: '000000006', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '曲丽丽 评论了你', + description: '描述信息描述信息描述信息', + datetime: '2017-08-07', + type: 'message', + clickClose: true, + }, + { + id: '000000007', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '朱偏右 回复了你', + description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', + datetime: '2017-08-07', + type: 'message', + clickClose: true, + }, + { + id: '000000008', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '标题', + description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', + datetime: '2017-08-07', + type: 'message', + clickClose: true, + }, + { + id: '000000009', + title: '任务名称', + description: '任务需要在 2017-01-12 20:00 前启动', + extra: '未开始', + status: 'todo', + type: 'event', + }, + { + id: '000000010', + title: '第三方紧急代码变更', + description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', + extra: '马上到期', + status: 'urgent', + type: 'event', + }, + { + id: '000000011', + title: '信息安全考试', + description: '指派竹尔于 2017-01-09 前完成更新并发布', + extra: '已耗时 8 天', + status: 'doing', + type: 'event', + }, + { + id: '000000012', + title: 'ABCD 版本发布', + description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', + extra: '进行中', + status: 'processing', + type: 'event', + }, + ], + }); +}; + +export default { + 'GET /api/notices': getNotices, +}; diff --git a/zlt-web/mock/route.ts b/zlt-web/mock/route.ts new file mode 100644 index 00000000..418d10f1 --- /dev/null +++ b/zlt-web/mock/route.ts @@ -0,0 +1,5 @@ +export default { + '/api/auth_routes': { + '/form/advanced-form': { authority: ['admin', 'user'] }, + }, +}; diff --git a/zlt-web/mock/user.ts b/zlt-web/mock/user.ts new file mode 100644 index 00000000..75edd340 --- /dev/null +++ b/zlt-web/mock/user.ts @@ -0,0 +1,203 @@ +import { Request, Response } from 'express'; + +const waitTime = (time: number = 100) => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(true); + }, time); + }); +}; + +async function getFakeCaptcha(req: Request, res: Response) { + await waitTime(2000); + return res.json('captcha-xxx'); +} + +const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION } = process.env; + +/** + * 当前用户的权限,如果为空代表没登录 + * current user access, if is '', user need login + * 如果是 pro 的预览,默认是有权限的 + */ +let access = ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site' ? 'admin' : ''; + +const getAccess = () => { + return access; +}; + +// 代码中会兼容本地 service mock 以及部署站点的静态数据 +export default { + // 支持值为 Object 和 Array + 'GET /api/currentUser': (req: Request, res: Response) => { + if (!getAccess()) { + res.status(401).send({ + data: { + isLogin: false, + }, + errorCode: '401', + errorMessage: '请先登录!', + success: true, + }); + return; + } + res.send({ + success: true, + data: { + name: 'Serati Ma', + avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png', + userid: '00000001', + email: 'antdesign@alipay.com', + signature: '海纳百川,有容乃大', + title: '交互专家', + group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED', + tags: [ + { + key: '0', + label: '很有想法的', + }, + { + key: '1', + label: '专注设计', + }, + { + key: '2', + label: '辣~', + }, + { + key: '3', + label: '大长腿', + }, + { + key: '4', + label: '川妹子', + }, + { + key: '5', + label: '海纳百川', + }, + ], + notifyCount: 12, + unreadCount: 11, + country: 'China', + access: getAccess(), + geographic: { + province: { + label: '浙江省', + key: '330000', + }, + city: { + label: '杭州市', + key: '330100', + }, + }, + address: '西湖区工专路 77 号', + phone: '0752-268888888', + }, + }); + }, + // GET POST 可省略 + 'GET /api/users': [ + { + key: '1', + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + }, + { + key: '2', + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + }, + { + key: '3', + name: 'Joe Black', + age: 32, + address: 'Sidney No. 1 Lake Park', + }, + ], + 'POST /api/login/account': async (req: Request, res: Response) => { + const { password, username, type } = req.body; + await waitTime(2000); + if (password === 'ant.design' && username === 'admin') { + res.send({ + status: 'ok', + type, + currentAuthority: 'admin', + }); + access = 'admin'; + return; + } + if (password === 'ant.design' && username === 'user') { + res.send({ + status: 'ok', + type, + currentAuthority: 'user', + }); + access = 'user'; + return; + } + if (type === 'mobile') { + res.send({ + status: 'ok', + type, + currentAuthority: 'admin', + }); + access = 'admin'; + return; + } + + res.send({ + status: 'error', + type, + currentAuthority: 'guest', + }); + access = 'guest'; + }, + 'POST /api/login/outLogin': (req: Request, res: Response) => { + access = ''; + res.send({ data: {}, success: true }); + }, + 'POST /api/register': (req: Request, res: Response) => { + res.send({ status: 'ok', currentAuthority: 'user', success: true }); + }, + 'GET /api/500': (req: Request, res: Response) => { + res.status(500).send({ + timestamp: 1513932555104, + status: 500, + error: 'error', + message: 'error', + path: '/base/category/list', + }); + }, + 'GET /api/404': (req: Request, res: Response) => { + res.status(404).send({ + timestamp: 1513932643431, + status: 404, + error: 'Not Found', + message: 'No message available', + path: '/base/category/list/2121212', + }); + }, + 'GET /api/403': (req: Request, res: Response) => { + res.status(403).send({ + timestamp: 1513932555104, + status: 403, + error: 'Forbidden', + message: 'Forbidden', + path: '/base/category/list', + }); + }, + 'GET /api/401': (req: Request, res: Response) => { + res.status(401).send({ + timestamp: 1513932555104, + status: 401, + error: 'Unauthorized', + message: 'Unauthorized', + path: '/base/category/list', + }); + }, + + 'GET /api/login/captcha': getFakeCaptcha, +}; diff --git a/zlt-web/package.json b/zlt-web/package.json new file mode 100644 index 00000000..861c55eb --- /dev/null +++ b/zlt-web/package.json @@ -0,0 +1,107 @@ +{ + "name": "ant-design-pro", + "version": "5.2.0", + "private": true, + "description": "An out-of-box UI solution for enterprise applications", + "scripts": { + "analyze": "cross-env ANALYZE=1 umi build", + "build": "umi build", + "deploy": "npm run build && npm run gh-pages", + "dev": "npm run start:dev", + "gh-pages": "gh-pages -d dist", + "i18n-remove": "pro i18n-remove --locale=zh-CN --write", + "postinstall": "umi g tmp", + "lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier && npm run tsc", + "lint-staged": "lint-staged", + "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ", + "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style", + "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src", + "lint:prettier": "prettier -c --write \"src/**/*\" --end-of-line auto", + "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less", + "openapi": "umi openapi", + "playwright": "playwright install && playwright test", + "prettier": "prettier -c --write \"src/**/*\"", + "serve": "umi-serve", + "start": "cross-env UMI_ENV=dev umi dev", + "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev umi dev", + "start:no-mock": "cross-env MOCK=none UMI_ENV=dev umi dev", + "start:no-ui": "cross-env UMI_UI=none UMI_ENV=dev umi dev", + "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev umi dev", + "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev umi dev", + "test": "umi test", + "test:component": "umi test ./src/components", + "test:e2e": "node ./tests/run-tests.js", + "tsc": "tsc --noEmit" + }, + "lint-staged": { + "**/*.less": "stylelint --syntax less", + "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js", + "**/*.{js,jsx,tsx,ts,less,md,json}": [ + "prettier --write" + ] + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 10" + ], + "dependencies": { + "@ant-design/charts": "^1.4.2", + "@ant-design/icons": "^4.7.0", + "@ant-design/pro-components": "1.1.1", + "@umijs/route-utils": "^2.0.0", + "antd": "^4.20.0", + "classnames": "^2.3.0", + "lodash": "^4.17.21", + "moment": "^2.29.0", + "omit.js": "^2.0.2", + "rc-menu": "^9.1.0", + "rc-resize-observer": "^1.2.0", + "rc-util": "^5.16.0", + "react": "^17.0.0", + "react-dev-inspector": "^1.7.0", + "react-dom": "^17.0.0", + "react-helmet-async": "^1.2.0", + "react-json-tree": "^0.17.0", + "treeify-js": "^1.0.8", + "umi": "^3.5.0", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@ant-design/pro-cli": "^2.1.0", + "@playwright/test": "^1.17.0", + "@types/classnames": "^2.3.1", + "@types/express": "^4.17.0", + "@types/history": "^4.7.0", + "@types/jest": "^26.0.0", + "@types/lodash": "^4.14.0", + "@types/react": "^17.0.0", + "@types/react-dom": "^17.0.0", + "@types/react-helmet": "^6.1.0", + "@types/uuid": "^8.3.4", + "@umijs/fabric": "^2.11.1", + "@umijs/openapi": "^1.6.0", + "@umijs/plugin-blocks": "^2.2.0", + "@umijs/plugin-esbuild": "^1.4.0", + "@umijs/plugin-openapi": "^1.3.3", + "@umijs/preset-ant-design-pro": "^1.3.0", + "@umijs/preset-dumi": "^1.1.0", + "@umijs/preset-react": "^2.1.0", + "cross-env": "^7.0.0", + "cross-port-killer": "^1.3.0", + "detect-installer": "^1.0.0", + "eslint": "^7.32.0", + "gh-pages": "^3.2.0", + "jsdom-global": "^3.0.0", + "lint-staged": "^10.0.0", + "mockjs": "^1.1.0", + "prettier": "^2.5.0", + "stylelint": "^13.0.0", + "swagger-ui-dist": "^4.12.0", + "typescript": "^4.5.0", + "umi-serve": "^1.9.10" + }, + "engines": { + "node": ">=12.0.0" + } +} diff --git a/zlt-web/playwright.config.ts b/zlt-web/playwright.config.ts new file mode 100644 index 00000000..ec1b31db --- /dev/null +++ b/zlt-web/playwright.config.ts @@ -0,0 +1,22 @@ +// playwright.config.ts +import type { PlaywrightTestConfig } from '@playwright/test'; +import { devices } from '@playwright/test'; + +const config: PlaywrightTestConfig = { + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + use: { + trace: 'on-first-retry', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + ], +}; +export default config; diff --git a/zlt-web/pom.xml b/zlt-web/pom.xml index 34169a1c..30676f7b 100644 --- a/zlt-web/pom.xml +++ b/zlt-web/pom.xml @@ -1,17 +1,118 @@ - - - 4.0.0 - - - com.zlt - central-platform - 5.4.0 - - zlt-web - 前端 - pom - - back-web - - + + + 4.0.0 + + + com.zlt + central-platform + 5.4.0 + + zlt-web + 前端 + pom + + v16.13.2 + v1.22.19 + + + + org.springframework.boot + spring-boot-starter-web + + + + + + com.github.eirslett + frontend-maven-plugin + 1.12.1 + + + install node and yarn + + install-node-and-yarn + + + ${node.version} + ${yarn.version} + + + + yarn install + generate-resources + + yarn + + + install + + + + yarn run build + compile + + yarn + + + run build + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.0 + + + woff + ttf + woff2 + eot + swf + ico + png + + true + + + + copy + compile + + resources + + + + + + + + + src/main/resources + + + dist + static + false + + + + + + noNode + + + + com.github.eirslett + frontend-maven-plugin + + true + + + + + + + diff --git a/zlt-web/public/CNAME b/zlt-web/public/CNAME new file mode 100644 index 00000000..30c2d4d3 --- /dev/null +++ b/zlt-web/public/CNAME @@ -0,0 +1 @@ +preview.pro.ant.design \ No newline at end of file diff --git a/zlt-web/public/campaign.svg b/zlt-web/public/campaign.svg new file mode 100644 index 00000000..71aa12f3 --- /dev/null +++ b/zlt-web/public/campaign.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zlt-web/public/favicon.ico b/zlt-web/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e2e93252988b5bed120ddeb168eb577bf0caa881 GIT binary patch literal 4286 zcmeHLO(?8k6#ga#Gs=ufvobTd=q@y~nOLdYlqL%nQY4WqC`)z}3y~cqOAAF4VkQd~ z^3$wrC}~D1l%!eMp!|gA&U5sN?~b{2>)yNg-s#Lc-+9k_p7Y<=XqqYcDJs(Vt%dBG z=F~Lpdy*pd!Y zozZT}udJ-#| zqiAVq0sT@kAMMobbULxOw+F6{j*egO8CQ?TgTuo^+}_@zrlv;l$*-)e#PRVl?(Xgo zi9`?zg>ZFsh0DuJ)Ya9!von7LPN@OfP9IfH_4tet&&I~a#O{TK1<3*LO-xJ( zZ*Fc5%v&m4#Z&mZySs8{XJ-fV^Yh@{p`ju8d_J)w6+U%`!(qAC+uJK~qg_o+O|QC` zTVg0Y{jSHqzP^^&G0t4^cwF+$`egj?@9$AtTMLuPB>7!lUKY8&zP?xd=H_PM(U;HS ztNi!(_oJes0<5X6tu4{BxVR{FO)_x3UauFkv$I%RTSHe@7dAIHF+4mhc?|>t(!XbCXVQZk z8yje7Xh2R*&WCwdw&?N4$H!4$Uyq)i9_;V$3;y)^-LKhmkv{Z#(CP^-7Wn# zI5-H>z`y`nTU%u=f7Tbh-mg5fPT0G8`Wx6^vD1(>-r0;AFlyjWYC!!D@UQlt)%}4^ literal 0 HcmV?d00001 diff --git a/zlt-web/public/icons/icon-128x128.png b/zlt-web/public/icons/icon-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..3d563c5f6d01e43a8f8566d244d1dde1c8d5bde7 GIT binary patch literal 1931 zcmd6o`#;oq8^%B1IWUG{FjJJ)NDeh9mD4&+(>NwEkZmQr>en?uH_ z#(AWM^;9N<7wfDkhDh6#BsQeYuFPX!`}`5l5BGKbc3t-`_xsNAaCgFCcVGbkI2UIc zeaqp$2P3zoBD;Y8Era6ePE^o1q%{wKyn_qvh*zTDV(GD5f;S;cwxE<_V}Lrn5*N@J z5dotWnQx04Psw9cQ@S-q=eL{Xo{P5$)!g)&cY=Z+{7Jg`EcVDR7< zw_D}(-I3}kr!Q2%|bsd@Vm7z2Os z2xxjyt0J^v5rAfwkF%{({RInXaof2OyeQRZk$1e~I@qcwdU z%PDWWpaxUMlEU`ef*>Ude!UPfI%M3HNLFU-O?n+y;OYpxDmr7)&m-w@^QB!QBgo(w zR?t{&4wT3ewOZF4c;h<<(=Ypv?G({~o850pLh2YB=G2J z%~R-&{Ibyr7rOjme#1w0b~V_jhwt6m7R*T18WHXf-k;)&+FE)$_$&=Ix)eA|X^^tX z)qsKIPjC&7uD%hj-P&$)6TvFfo_`lwnN^z0dBhSBz=hLd!$(qfvqgnthO)f8=WAQa zjm$41H5(2aB~A+{brAe7;S14)@ec`RZ3UKe%yDfTGtCSw$S) zr}T_TPPsI#3PWir8KktTt$)KNS|e-1^)Qq})5I{J$ZnN~V=)SQ)T-5Bnz;mr-7O0O zF%vvj5Y-mtp{uc?LV1&rN$@m;@RGs{ad;vbHVLkqJe>z7F8=3818JoW__a(cL;S_B zgtgkEn{&RpU-~r%!#Lou$QwCG+Lx;Ez7R)0h|>eNC&Tr(iLu#S@v)FI5=V77>YH2r zsho`_!l%IBuIi)JV13OgXMq~A!*gV~mHS!dss{Sc@|4$Kh3ADD7nTaNAbwj8X=TCx z&U8fc`KY}Je59v2#3_tbtDDUM5iC~hBFVYf^J?vmw7 zq?Z!a!={)B(nXskHNBr&Z~5h6oes-TRjYpn0Ir=?4C2|Mwu&Msz|%GZ&^85Q*X~wz zulF~xL!**C$SEq-f?%U!-|L`CU~(nUW3_|b89z_F-@gY)lESM9w9Rqgcfd7*dH@Q` zsBzKDEbr6_OVxTg(qu_3C@LMdOx4*Fa!AD*tSz5S>YA$4? ziU(8IEqFe88x-W4=wZWS3~W|cK&%ySoZwKc&OETW26}A=80Bh2J5LYmgWK;=^T7nm z${~-mVvqO~a?PuffMA|4oSu!4{t>yEoS0mu+J)Sm=uAkY^3ewbSO!> z4_9MU-oiMShFdy4o=y2 zicG%}(yL)MvQk|=V(_}Rfk{t70S0b&PT=u5o=y@>k4>}*TtAd14*TIf*!Zv+lp=GjiSl;Wn6K%a!6{bL?5%o7c_jXO(wPsaI z+5N}ssu0W-S3L1LndkQ`BX@WP!r6L!k+Zn#>5db2L@O!gNozG9K14=?*!D z65gG%s&@c!ZG>WDRZtu~$KM9^zNSYBXdtS+ROE{yWglynjQL|b(;IosL+q{Z3S1oA KX^m87#(x1vFj@ov literal 0 HcmV?d00001 diff --git a/zlt-web/public/icons/icon-192x192.png b/zlt-web/public/icons/icon-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..f44a0f0bb2cbc1f38554f96892fc7171a93b2c19 GIT binary patch literal 3161 zcmeHJ`8U*iAOC!3CWaVekGR|s&KsD|8R$u5bQ$CF$m>&R9ymLw$#musDr2-%lR zVT76%J5!b!l6|>kFo- znw~YbSXcu2SulXV8jMzCFuU3o3dz($KXu$YF9SrSFiI^hQIP@)o4@>&Ux3 zQT+Py;tb2#Ab=n%6xF~Hl-~KmP#8_Xeh7kD&#u`SKm;DOMF178ZmH&iqwus~GO!Qd z5wijrQD*vhpw<|Xkhc%)^_pj>4wS23=E=v9I|U*o#)xGHTzJJc>?!8t!-gJS8|(zS zTS&j;Xin^0B@A6SrD?NS%ve3CQkEA>SYPdjT5fA4Hy6!}>aVe!zh+kX160o7je)W4 zm24OZNPiW1bFv^0!Cbz(7W0I9M{H!q4#o-<=nMjP^VgtN;G3$A8sOpkon4B!S zC1!Du^~E5EE>8A!4}M07%!RLL;wpw98-rfoRn)|!nJ+N*B3a6ttVrMEbVq&AqjYPq z*F;U&{wk6nf0Z@7r#56|UwlY+R4taWZ{(O;LYS-FRQXInrh<(%-Psl%Krurb2W5SHBZpg^Ik zJ4#We$neiWS2u&%@Q{PtI$^F+w_UO-b5UZGWN@TrzESQ4E02$i)iwuZB%e3oIBN=A z?%G_V)Ti$`Q2f@F7!_8qPaD@=16O-Nil_^DUyy_W%(exG7T@%Pr3LV>{&=zPLy4?k z(p@`2o9VnqJZq^pwl;`x7*!-Qe_TS&e|8duC&pPt>byAq4-MIUDeywv8Y@S$Q44f$ zlb3b^Dl=-olJH%@bBBBbXQu`5shL(AJqI);s)Jon0;d8!npiL26y#w*0I|Qou%|XB zyvyly55{5VN0DEySi5M-a*MW5=NAQ#a=|++{LHg3GxFO*+Q*=bRQAGMthNfCi(w_OCa`YowrF)z%pVMZj6D=N_}a zjlbrDmKLP);i=hC&ukqbSk-gHjL9X^(*6I9>%C}0cfyZIib%|kEzf_$( zQM%9xnGT!?RB^E_T3rua_nX3F-6M{tDG5foZ?Y~Z!*%zuKW{Rz1PI3zyaxx>aT`?y;aJtXi|Z%GM~>^Q&d zoxyD(-d?|xsW$3`#5YCokeo+!Bgx~=ElBD;Gz`5Jhncx+$36r`>HalACP@73`ST03 z0OAjUu_pJI8zg;b*;CThg8RL`;)%f3NFLJ&MxNY5ebtPhd|n76T~F27RY~>>$5{rNN zRtTvUN@%i0-M4NcFV%~!H)*2eiW9rRZ!dUZylq<|S}yIJ1~;SbSkiQ2AHxv8`E8~o zq|F2*i8|AM3m{TKouvOY1;-U(3fj5krdMj_1+x{6V+hKSlZM63dOr#K%>!X$c9hpz zQ#Ra&0IbhjQ4I-w#ZkL6P4L`a$;?8#^ z;d=+%dT@5Q=r3d&Sfys}z__?q{E2(_Kqy z>Z523cjMF1OpMnog3!Ca$ba|mg_HQXa9yl;TXrf)vU<-CJE}T8$RY9OH-*`XSy{Xm zfe`|j_4R=kipmNcWq^>MxZzwY3}6I7Q~DkR8N_D$mFU3mpj3gcfeg^(WVX-18Gs~f zD=SE%0Sq13^n3^jpo%!<2^crbsI%T-KO_$r$+0eYfW*@`>xfDKL6d%%yq6n>)EhnT z!>xMZv`8St4O5sNE=~k!;CM;+6r&(N*<|u+_X_$jS_UY(<)_uvF(C8%1<|eoPM-_x5B502=S>>1XnhkE8BPYR}bZMl= zSbtw4bJb^<(YzkOFh2tudwrz!-P4x}F)2>GV|uvcLFl>9!twjfe{33%A8?B=t#_Pv zcy;`}yn#8di_E{p(Ld5L>BSv;$a~SsSJL^{lW^#+J}3*GANqtjBU>@>d~$c1hgRW~ zsxyrUysVMvbegvc`?p4_&em8J9vh#u313=_9?}mJq+g$*{mLsAqdzrYp4Zv;z(o$y zMAaoLpTW3YzWmr6K}FC-?0=6tB}Bw(pBmQJ=9?6S6GYqxQ&8K@a0K~}|5ivJ0w3`O avKvCS9bN*c30(!iJ*K}}8kZRnqW=XCZIR~y literal 0 HcmV?d00001 diff --git a/zlt-web/public/icons/icon-512x512.png b/zlt-web/public/icons/icon-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..00e3b022179faadb7cd1d3323e20da284ccbac43 GIT binary patch literal 14340 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 literal 0 HcmV?d00001 diff --git a/zlt-web/public/logo.svg b/zlt-web/public/logo.svg new file mode 100644 index 00000000..239bf69f --- /dev/null +++ b/zlt-web/public/logo.svg @@ -0,0 +1 @@ +Group 28 Copy 5Created with Sketch. \ No newline at end of file diff --git a/zlt-web/public/pro_icon.svg b/zlt-web/public/pro_icon.svg new file mode 100644 index 00000000..e075b78d --- /dev/null +++ b/zlt-web/public/pro_icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/zlt-web/src/access.ts b/zlt-web/src/access.ts new file mode 100644 index 00000000..e823e24b --- /dev/null +++ b/zlt-web/src/access.ts @@ -0,0 +1,9 @@ +/** + * @see https://umijs.org/zh-CN/plugins/plugin-access + * */ +export default function access(initialState: { currentUser?: API.CurrentUser } | undefined) { + const { currentUser } = initialState ?? {}; + return { + canAdmin: currentUser && currentUser.access === 'admin', + }; +} diff --git a/zlt-web/src/app.tsx b/zlt-web/src/app.tsx new file mode 100644 index 00000000..f3c68f30 --- /dev/null +++ b/zlt-web/src/app.tsx @@ -0,0 +1,302 @@ +import Footer from '@/components/Footer'; +import RightContent from '@/components/RightContent'; +import { + AppstoreOutlined, + MenuOutlined, + TeamOutlined, + SettingOutlined, + UserOutlined, + CaretDownFilled, + SmileOutlined, +} from '@ant-design/icons'; +import type { MenuDataItem, Settings as LayoutSettings } from '@ant-design/pro-components'; +import { PageLoading, SettingDrawer } from '@ant-design/pro-components'; +import { Divider, Dropdown, Menu, Space } from 'antd'; +import type { RequestConfig, RunTimeLayoutConfig } from 'umi'; +import { history } from 'umi'; +import defaultSettings from '../config/defaultSettings'; +import { currentUser as queryCurrentUser, fetchMenuData } from './services/ant-design-pro/api'; + +const isDev = process.env.NODE_ENV === 'development'; +const loginPath = '/user/login'; + +/** 获取用户信息比较慢的时候会展示一个 loading */ +export const initialStateConfig = { + loading: , +}; + +/** + * @see https://umijs.org/zh-CN/plugins/plugin-initial-state + * */ +export async function getInitialState(): Promise<{ + settings?: Partial; + currentUser?: API.CurrentUser; + loading?: boolean; + fetchUserInfo?: () => Promise; +}> { + const fetchUserInfo = async () => { + try { + const msg = await queryCurrentUser(); + // TODO + return msg.datas; + } catch (error) { + history.push(loginPath); + } + return undefined; + }; + // 如果不是登录页面,执行 + if (history.location.pathname !== loginPath) { + const currentUser = await fetchUserInfo(); + return { + fetchUserInfo, + currentUser, + settings: defaultSettings, + }; + } + return { + fetchUserInfo, + settings: defaultSettings, + }; +} + +// ProLayout 支持的api https://procomponents.ant.design/components/layout +export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => { + return { + rightContentRender: () => , + disableContentMargin: false, + waterMarkProps: { + content: initialState?.currentUser?.username, + }, + footerRender: () =>