From 51368dac7b8b83dc42a75170a6fcf912930b2b2b Mon Sep 17 00:00:00 2001 From: csp <1165680007@qq.com> Date: Fri, 6 May 2022 16:00:24 +0800 Subject: [PATCH] =?UTF-8?q?onepiece=E7=A4=BE=E5=8C=BA=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 16 + .eslintignore | 8 + .eslintrc.js | 8 + .gitignore | 40 ++ .husky/.gitignore | 1 + .husky/commit-msg | 7 + .husky/pre-commit | 4 + .prettierignore | 23 + .prettierrc.js | 5 + .stylelintrc.js | 3 + .vscode/extensions.json | 8 + .vscode/settings.json | 5 + config/config.dev.js | 14 + config/config.js | 75 +++ config/defaultSettings.js | 15 + config/oneapi.json | 593 ++++++++++++++++++ config/proxy.js | 38 ++ config/routes.js | 53 ++ jest.config.js | 9 + jsconfig.json | 11 + mock/listTableList.js | 177 ++++++ mock/notices.js | 105 ++++ mock/route.js | 7 + mock/user.js | 210 +++++++ package.json | 98 +++ playwright.config.js | 20 + public/CNAME | 1 + public/favicon.ico | Bin 0 -> 4286 bytes public/icons/icon-128x128.png | Bin 0 -> 1329 bytes public/icons/icon-192x192.png | Bin 0 -> 1856 bytes public/icons/icon-512x512.png | Bin 0 -> 5082 bytes public/logo.svg | 1 + public/pro_icon.svg | 5 + src/access.js | 9 + src/app.jsx | 98 +++ src/components/Footer/index.jsx | 39 ++ src/components/HeaderDropdown/index.jsx | 10 + src/components/HeaderDropdown/index.less | 16 + src/components/HeaderSearch/index.jsx | 83 +++ src/components/HeaderSearch/index.less | 25 + src/components/NoticeIcon/NoticeIcon.jsx | 114 ++++ src/components/NoticeIcon/NoticeList.jsx | 97 +++ src/components/NoticeIcon/NoticeList.less | 103 +++ src/components/NoticeIcon/index.jsx | 148 +++++ src/components/NoticeIcon/index.less | 35 ++ .../RightContent/AvatarDropdown.jsx | 98 +++ src/components/RightContent/index.jsx | 64 ++ src/components/RightContent/index.less | 84 +++ src/components/index.md | 272 ++++++++ src/e2e/baseLayout.e2e.spec.js | 47 ++ src/global.jsx | 108 ++++ src/global.less | 57 ++ src/locales/bn-BD.js | 25 + src/locales/bn-BD/component.js | 5 + src/locales/bn-BD/globalHeader.js | 17 + src/locales/bn-BD/menu.js | 52 ++ src/locales/bn-BD/pages.js | 70 +++ src/locales/bn-BD/pwa.js | 7 + src/locales/bn-BD/settingDrawer.js | 31 + src/locales/bn-BD/settings.js | 59 ++ src/locales/en-US.js | 24 + src/locales/en-US/component.js | 5 + src/locales/en-US/globalHeader.js | 17 + src/locales/en-US/menu.js | 52 ++ src/locales/en-US/pages.js | 70 +++ src/locales/en-US/pwa.js | 6 + src/locales/en-US/settingDrawer.js | 31 + src/locales/en-US/settings.js | 60 ++ src/locales/fa-IR.js | 23 + src/locales/fa-IR/component.js | 5 + src/locales/fa-IR/globalHeader.js | 17 + src/locales/fa-IR/menu.js | 52 ++ src/locales/fa-IR/pages.js | 67 ++ src/locales/fa-IR/pwa.js | 7 + src/locales/fa-IR/settingDrawer.js | 32 + src/locales/fa-IR/settings.js | 60 ++ src/locales/id-ID.js | 24 + src/locales/id-ID/component.js | 5 + src/locales/id-ID/globalHeader.js | 17 + src/locales/id-ID/menu.js | 52 ++ src/locales/id-ID/pages.js | 70 +++ src/locales/id-ID/pwa.js | 7 + src/locales/id-ID/settingDrawer.js | 32 + src/locales/id-ID/settings.js | 60 ++ src/locales/ja-JP.js | 23 + src/locales/ja-JP/component.js | 5 + src/locales/ja-JP/globalHeader.js | 17 + src/locales/ja-JP/menu.js | 52 ++ src/locales/ja-JP/pages.js | 67 ++ src/locales/ja-JP/pwa.js | 7 + src/locales/ja-JP/settingDrawer.js | 31 + src/locales/ja-JP/settings.js | 59 ++ src/locales/pt-BR.js | 21 + src/locales/pt-BR/component.js | 5 + src/locales/pt-BR/globalHeader.js | 18 + src/locales/pt-BR/menu.js | 52 ++ src/locales/pt-BR/pages.js | 70 +++ src/locales/pt-BR/pwa.js | 7 + src/locales/pt-BR/settingDrawer.js | 32 + src/locales/pt-BR/settings.js | 60 ++ src/locales/zh-CN.js | 24 + src/locales/zh-CN/component.js | 5 + src/locales/zh-CN/globalHeader.js | 17 + src/locales/zh-CN/menu.js | 52 ++ src/locales/zh-CN/pages.js | 67 ++ src/locales/zh-CN/pwa.js | 6 + src/locales/zh-CN/settingDrawer.js | 31 + src/locales/zh-CN/settings.js | 55 ++ src/locales/zh-TW.js | 19 + src/locales/zh-TW/component.js | 5 + src/locales/zh-TW/globalHeader.js | 17 + src/locales/zh-TW/menu.js | 52 ++ src/locales/zh-TW/pwa.js | 6 + src/locales/zh-TW/settingDrawer.js | 31 + src/locales/zh-TW/settings.js | 55 ++ src/manifest.json | 22 + src/pages/404.jsx | 18 + src/pages/Admin.jsx | 55 ++ src/pages/TableList/components/UpdateForm.jsx | 196 ++++++ src/pages/TableList/index.jsx | 403 ++++++++++++ src/pages/Welcome.jsx | 65 ++ src/pages/Welcome.less | 8 + src/pages/document.ejs | 236 +++++++ src/pages/user/Login/index.jsx | 288 +++++++++ src/pages/user/Login/index.less | 50 ++ src/service-worker.js | 65 ++ src/services/ant-design-pro/api.js | 73 +++ src/services/ant-design-pro/index.js | 11 + src/services/ant-design-pro/login.js | 13 + src/services/swagger/index.js | 13 + src/services/swagger/pet.js | 110 ++++ src/services/swagger/store.js | 41 ++ src/services/swagger/user.js | 79 +++ tests/run-tests.js | 47 ++ tests/setupTests.js | 10 + 135 files changed, 6899 insertions(+) create mode 100644 .editorconfig create mode 100644 .eslintignore create mode 100644 .eslintrc.js create mode 100644 .gitignore create mode 100644 .husky/.gitignore create mode 100644 .husky/commit-msg create mode 100644 .husky/pre-commit create mode 100644 .prettierignore create mode 100644 .prettierrc.js create mode 100644 .stylelintrc.js create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 config/config.dev.js create mode 100644 config/config.js create mode 100644 config/defaultSettings.js create mode 100644 config/oneapi.json create mode 100644 config/proxy.js create mode 100644 config/routes.js create mode 100644 jest.config.js create mode 100644 jsconfig.json create mode 100644 mock/listTableList.js create mode 100644 mock/notices.js create mode 100644 mock/route.js create mode 100644 mock/user.js create mode 100644 package.json create mode 100644 playwright.config.js create mode 100644 public/CNAME create mode 100644 public/favicon.ico create mode 100644 public/icons/icon-128x128.png create mode 100644 public/icons/icon-192x192.png create mode 100644 public/icons/icon-512x512.png create mode 100644 public/logo.svg create mode 100644 public/pro_icon.svg create mode 100644 src/access.js create mode 100644 src/app.jsx create mode 100644 src/components/Footer/index.jsx create mode 100644 src/components/HeaderDropdown/index.jsx create mode 100644 src/components/HeaderDropdown/index.less create mode 100644 src/components/HeaderSearch/index.jsx create mode 100644 src/components/HeaderSearch/index.less create mode 100644 src/components/NoticeIcon/NoticeIcon.jsx create mode 100644 src/components/NoticeIcon/NoticeList.jsx create mode 100644 src/components/NoticeIcon/NoticeList.less create mode 100644 src/components/NoticeIcon/index.jsx create mode 100644 src/components/NoticeIcon/index.less create mode 100644 src/components/RightContent/AvatarDropdown.jsx create mode 100644 src/components/RightContent/index.jsx create mode 100644 src/components/RightContent/index.less create mode 100644 src/components/index.md create mode 100644 src/e2e/baseLayout.e2e.spec.js create mode 100644 src/global.jsx create mode 100644 src/global.less create mode 100644 src/locales/bn-BD.js create mode 100644 src/locales/bn-BD/component.js create mode 100644 src/locales/bn-BD/globalHeader.js create mode 100644 src/locales/bn-BD/menu.js create mode 100644 src/locales/bn-BD/pages.js create mode 100644 src/locales/bn-BD/pwa.js create mode 100644 src/locales/bn-BD/settingDrawer.js create mode 100644 src/locales/bn-BD/settings.js create mode 100644 src/locales/en-US.js create mode 100644 src/locales/en-US/component.js create mode 100644 src/locales/en-US/globalHeader.js create mode 100644 src/locales/en-US/menu.js create mode 100644 src/locales/en-US/pages.js create mode 100644 src/locales/en-US/pwa.js create mode 100644 src/locales/en-US/settingDrawer.js create mode 100644 src/locales/en-US/settings.js create mode 100644 src/locales/fa-IR.js create mode 100644 src/locales/fa-IR/component.js create mode 100644 src/locales/fa-IR/globalHeader.js create mode 100644 src/locales/fa-IR/menu.js create mode 100644 src/locales/fa-IR/pages.js create mode 100644 src/locales/fa-IR/pwa.js create mode 100644 src/locales/fa-IR/settingDrawer.js create mode 100644 src/locales/fa-IR/settings.js create mode 100644 src/locales/id-ID.js create mode 100644 src/locales/id-ID/component.js create mode 100644 src/locales/id-ID/globalHeader.js create mode 100644 src/locales/id-ID/menu.js create mode 100644 src/locales/id-ID/pages.js create mode 100644 src/locales/id-ID/pwa.js create mode 100644 src/locales/id-ID/settingDrawer.js create mode 100644 src/locales/id-ID/settings.js create mode 100644 src/locales/ja-JP.js create mode 100644 src/locales/ja-JP/component.js create mode 100644 src/locales/ja-JP/globalHeader.js create mode 100644 src/locales/ja-JP/menu.js create mode 100644 src/locales/ja-JP/pages.js create mode 100644 src/locales/ja-JP/pwa.js create mode 100644 src/locales/ja-JP/settingDrawer.js create mode 100644 src/locales/ja-JP/settings.js create mode 100644 src/locales/pt-BR.js create mode 100644 src/locales/pt-BR/component.js create mode 100644 src/locales/pt-BR/globalHeader.js create mode 100644 src/locales/pt-BR/menu.js create mode 100644 src/locales/pt-BR/pages.js create mode 100644 src/locales/pt-BR/pwa.js create mode 100644 src/locales/pt-BR/settingDrawer.js create mode 100644 src/locales/pt-BR/settings.js create mode 100644 src/locales/zh-CN.js create mode 100644 src/locales/zh-CN/component.js create mode 100644 src/locales/zh-CN/globalHeader.js create mode 100644 src/locales/zh-CN/menu.js create mode 100644 src/locales/zh-CN/pages.js create mode 100644 src/locales/zh-CN/pwa.js create mode 100644 src/locales/zh-CN/settingDrawer.js create mode 100644 src/locales/zh-CN/settings.js create mode 100644 src/locales/zh-TW.js create mode 100644 src/locales/zh-TW/component.js create mode 100644 src/locales/zh-TW/globalHeader.js create mode 100644 src/locales/zh-TW/menu.js create mode 100644 src/locales/zh-TW/pwa.js create mode 100644 src/locales/zh-TW/settingDrawer.js create mode 100644 src/locales/zh-TW/settings.js create mode 100644 src/manifest.json create mode 100644 src/pages/404.jsx create mode 100644 src/pages/Admin.jsx create mode 100644 src/pages/TableList/components/UpdateForm.jsx create mode 100644 src/pages/TableList/index.jsx create mode 100644 src/pages/Welcome.jsx create mode 100644 src/pages/Welcome.less create mode 100644 src/pages/document.ejs create mode 100644 src/pages/user/Login/index.jsx create mode 100644 src/pages/user/Login/index.less create mode 100644 src/service-worker.js create mode 100644 src/services/ant-design-pro/api.js create mode 100644 src/services/ant-design-pro/index.js create mode 100644 src/services/ant-design-pro/login.js create mode 100644 src/services/swagger/index.js create mode 100644 src/services/swagger/pet.js create mode 100644 src/services/swagger/store.js create mode 100644 src/services/swagger/user.js create mode 100644 tests/run-tests.js create mode 100644 tests/setupTests.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7e3649a --- /dev/null +++ b/.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/.eslintignore b/.eslintignore new file mode 100644 index 0000000..8336e93 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,8 @@ +/lambda/ +/scripts +/config +.history +public +dist +.umi +mock \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..b882c20 --- /dev/null +++ b/.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/.gitignore b/.gitignore new file mode 100644 index 0000000..21ab9fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# 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 + +# 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/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 0000000..31354ec --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..d50cdcf --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,7 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +# Export Git hook params +export GIT_PARAMS=$* + +npx --no-install fabric verify-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..d37daa0 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx --no-install lint-staged diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..d17efb4 --- /dev/null +++ b/.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/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..7b597d7 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,5 @@ +const fabric = require('@umijs/fabric'); + +module.exports = { + ...fabric.prettier, +}; diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 0000000..a1184de --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@umijs/fabric/dist/stylelint')], +}; diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..33f300d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "esbenp.prettier-vscode", + "dbaeumer.vscode-eslint", + "stylelint.vscode-stylelint", + "wangzy.sneak-mark" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a5d9d03 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.formatOnSave": true, + "prettier.requireConfig": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" +} diff --git a/config/config.dev.js b/config/config.dev.js new file mode 100644 index 0000000..8e33701 --- /dev/null +++ b/config/config.dev.js @@ -0,0 +1,14 @@ +// 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/config/config.js b/config/config.js new file mode 100644 index 0000000..7110b42 --- /dev/null +++ b/config/config.js @@ -0,0 +1,75 @@ +// 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: true, + 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/config/defaultSettings.js b/config/defaultSettings.js new file mode 100644 index 0000000..be689e1 --- /dev/null +++ b/config/defaultSettings.js @@ -0,0 +1,15 @@ +const Settings = { + navTheme: 'light', + // 拂晓蓝 + primaryColor: '#1890ff', + layout: 'mix', + contentWidth: 'Fluid', + fixedHeader: false, + fixSiderbar: true, + colorWeak: false, + title: 'Ant Design Pro', + pwa: false, + logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg', + iconfontUrl: '', +}; +export default Settings; diff --git a/config/oneapi.json b/config/oneapi.json new file mode 100644 index 0000000..c77d988 --- /dev/null +++ b/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/config/proxy.js b/config/proxy.js new file mode 100644 index 0000000..49a4625 --- /dev/null +++ b/config/proxy.js @@ -0,0 +1,38 @@ +/** + * 在生产环境 代理是无法生效的,所以这里没有生产环境的配置 + * ------------------------------- + * 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, + }, + }, + test: { + '/api/': { + target: 'https://proapi.azurewebsites.net', + changeOrigin: true, + pathRewrite: { + '^': '', + }, + }, + }, + pre: { + '/api/': { + target: 'your pre url', + changeOrigin: true, + pathRewrite: { + '^': '', + }, + }, + }, +}; diff --git a/config/routes.js b/config/routes.js new file mode 100644 index 0000000..39803fb --- /dev/null +++ b/config/routes.js @@ -0,0 +1,53 @@ +export default [ + { + path: '/user', + layout: false, + routes: [ + { + name: 'login', + path: '/user/login', + component: './user/Login', + }, + { + component: './404', + }, + ], + }, + { + path: '/welcome', + name: 'welcome', + icon: 'smile', + component: './Welcome', + }, + { + path: '/admin', + name: 'admin', + icon: 'crown', + access: 'canAdmin', + component: './Admin', + routes: [ + { + path: '/admin/sub-page', + name: 'sub-page', + icon: 'smile', + component: './Welcome', + }, + { + component: './404', + }, + ], + }, + { + name: 'list.table-list', + icon: 'table', + path: '/list', + component: './TableList', + }, + { + path: '/', + redirect: '/welcome', + }, + { + component: './404', + }, +]; diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..4729573 --- /dev/null +++ b/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/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..197bee5 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "jsx": "react-jsx", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/mock/listTableList.js b/mock/listTableList.js new file mode 100644 index 0000000..b02c454 --- /dev/null +++ b/mock/listTableList.js @@ -0,0 +1,177 @@ +import moment from 'moment'; +import { parse } from 'url'; // mock tableListDataSource + +const genList = (current, pageSize) => { + const tableListDataSource = []; + + 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, res, u) { + 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; + let dataSource = [...tableListDataSource].slice((current - 1) * pageSize, current * pageSize); + + 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); + + 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, res, u, b) { + 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 = { + 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/mock/notices.js b/mock/notices.js new file mode 100644 index 0000000..7efbf77 --- /dev/null +++ b/mock/notices.js @@ -0,0 +1,105 @@ +const getNotices = (req, res) => { + 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/mock/route.js b/mock/route.js new file mode 100644 index 0000000..a6deca8 --- /dev/null +++ b/mock/route.js @@ -0,0 +1,7 @@ +export default { + '/api/auth_routes': { + '/form/advanced-form': { + authority: ['admin', 'user'], + }, + }, +}; diff --git a/mock/user.js b/mock/user.js new file mode 100644 index 0000000..fa8c1b4 --- /dev/null +++ b/mock/user.js @@ -0,0 +1,210 @@ +const waitTime = (time = 100) => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(true); + }, time); + }); +}; + +async function getFakeCaptcha(req, res) { + 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, res) => { + 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, res) => { + 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, res) => { + access = ''; + res.send({ + data: {}, + success: true, + }); + }, + 'POST /api/register': (req, res) => { + res.send({ + status: 'ok', + currentAuthority: 'user', + success: true, + }); + }, + 'GET /api/500': (req, res) => { + res.status(500).send({ + timestamp: 1513932555104, + status: 500, + error: 'error', + message: 'error', + path: '/base/category/list', + }); + }, + 'GET /api/404': (req, res) => { + res.status(404).send({ + timestamp: 1513932643431, + status: 404, + error: 'Not Found', + message: 'No message available', + path: '/base/category/list/2121212', + }); + }, + 'GET /api/403': (req, res) => { + res.status(403).send({ + timestamp: 1513932555104, + status: 403, + error: 'Forbidden', + message: 'Forbidden', + path: '/base/category/list', + }); + }, + 'GET /api/401': (req, res) => { + res.status(401).send({ + timestamp: 1513932555104, + status: 401, + error: 'Unauthorized', + message: 'Unauthorized', + path: '/base/category/list', + }); + }, + 'GET /api/login/captcha': getFakeCaptcha, +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..6b55e52 --- /dev/null +++ b/package.json @@ -0,0 +1,98 @@ +{ + "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", + "prepare": "husky install", + "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/icons": "^4.7.0", + "@ant-design/pro-card": "^1.19.0", + "@ant-design/pro-descriptions": "^1.10.0", + "@ant-design/pro-form": "^1.64.0", + "@ant-design/pro-layout": "^6.35.0", + "@ant-design/pro-table": "^2.71.0", + "@umijs/route-utils": "^2.0.0", + "antd": "^4.19.0", + "classnames": "^2.3.0", + "lodash": "^4.17.0", + "moment": "^2.29.0", + "omit.js": "^2.0.2", + "rc-menu": "^9.1.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", + "umi": "^3.5.0" + }, + "devDependencies": { + "@ant-design/pro-cli": "^2.1.0", + "@playwright/test": "^1.17.0", + "@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", + "@umijs/fabric": "^2.8.0", + "@umijs/openapi": "^1.3.0", + "@umijs/plugin-blocks": "^2.2.0", + "@umijs/plugin-esbuild": "^1.4.0", + "@umijs/plugin-openapi": "^1.3.0", + "@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", + "husky": "^7.0.4", + "jsdom-global": "^3.0.0", + "lint-staged": "^10.0.0", + "mockjs": "^1.1.0", + "prettier": "^2.5.0", + "stylelint": "^13.0.0", + "swagger-ui-react": "^3.52.0", + "typescript": "^4.5.0", + "umi-serve": "^1.9.10" + }, + "engines": { "node": ">=12.0.0" } +} diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..9b554d0 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,20 @@ +// playwright.config.ts +import { devices } from '@playwright/test'; +const config = { + 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/public/CNAME b/public/CNAME new file mode 100644 index 0000000..30c2d4d --- /dev/null +++ b/public/CNAME @@ -0,0 +1 @@ +preview.pro.ant.design \ No newline at end of file diff --git a/public/favicon.ico b/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/public/icons/icon-128x128.png b/public/icons/icon-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..48d0e2339a60a637b94319c65e8654289b4f4b6c GIT binary patch literal 1329 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

*C7T$?5!b= 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 28 Copy 5Created with Sketch. \ No newline at end of file diff --git a/public/pro_icon.svg b/public/pro_icon.svg new file mode 100644 index 0000000..e075b78 --- /dev/null +++ b/public/pro_icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/access.js b/src/access.js new file mode 100644 index 0000000..209b095 --- /dev/null +++ b/src/access.js @@ -0,0 +1,9 @@ +/** + * @see https://umijs.org/zh-CN/plugins/plugin-access + * */ +export default function access(initialState) { + const { currentUser } = initialState ?? {}; + return { + canAdmin: currentUser && currentUser.access === 'admin', + }; +} diff --git a/src/app.jsx b/src/app.jsx new file mode 100644 index 0000000..2b722a4 --- /dev/null +++ b/src/app.jsx @@ -0,0 +1,98 @@ +import { SettingDrawer } from '@ant-design/pro-layout'; +import { PageLoading } from '@ant-design/pro-layout'; +import { history, Link } from 'umi'; +import RightContent from '@/components/RightContent'; +import Footer from '@/components/Footer'; +import { currentUser as queryCurrentUser } from './services/ant-design-pro/api'; +import { BookOutlined, LinkOutlined } from '@ant-design/icons'; +import defaultSettings from '../config/defaultSettings'; +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() { + const fetchUserInfo = async () => { + try { + const msg = await queryCurrentUser(); + return msg.data; + } 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 = ({ initialState, setInitialState }) => { + return { + rightContentRender: () => , + disableContentMargin: false, + waterMarkProps: { + content: initialState?.currentUser?.name, + }, + footerRender: () =>