ソースを参照

第一次提交

zhaojijng 3 年 前
コミット
e5ee6a6448
100 ファイル変更3062 行追加0 行削除
  1. 16 0
      .editorconfig
  2. 8 0
      .eslintignore
  3. 8 0
      .eslintrc.js
  4. 40 0
      .gitignore
  5. 23 0
      .prettierignore
  6. 5 0
      .prettierrc.js
  7. 5 0
      .stylelintrc.js
  8. 8 0
      .vscode/extensions.json
  9. 5 0
      .vscode/settings.json
  10. 57 0
      README.md
  11. 15 0
      config/config.dev.ts
  12. 73 0
      config/config.ts
  13. 21 0
      config/defaultSettings.ts
  14. 593 0
      config/oneapi.json
  15. 34 0
      config/proxy.ts
  16. 46 0
      config/routes.ts
  17. 9 0
      jest.config.js
  18. 11 0
      jsconfig.json
  19. 174 0
      mock/listTableList.ts
  20. 107 0
      mock/notices.ts
  21. 5 0
      mock/route.ts
  22. 203 0
      mock/user.ts
  23. 114 0
      package.json
  24. 22 0
      playwright.config.ts
  25. 1 0
      public/CNAME
  26. BIN
      public/favicon.ico
  27. BIN
      public/icons/icon-128x128.png
  28. BIN
      public/icons/icon-192x192.png
  29. BIN
      public/icons/icon-512x512.png
  30. 1 0
      public/logo.svg
  31. 5 0
      public/pro_icon.svg
  32. 9 0
      src/access.ts
  33. 86 0
      src/antd-reset.less
  34. 26 0
      src/antd-tenants.less
  35. 103 0
      src/app.tsx
  36. BIN
      src/assets/fonts/Montserrat-Regular.woff2
  37. 68 0
      src/assets/images/empty-apply.svg
  38. 52 0
      src/assets/images/empty.svg
  39. 11 0
      src/assets/images/message-error.svg
  40. 11 0
      src/assets/images/message-info.svg
  41. 10 0
      src/assets/images/message-success.svg
  42. 3 0
      src/assets/images/page-enviroment/air.svg
  43. 8 0
      src/assets/images/page-enviroment/airMapTop.svg
  44. 73 0
      src/assets/images/page-enviroment/airTemp.svg
  45. 3 0
      src/assets/images/page-enviroment/all.svg
  46. BIN
      src/assets/images/page-enviroment/chartTemp.png
  47. 3 0
      src/assets/images/page-enviroment/close.svg
  48. 4 0
      src/assets/images/page-enviroment/co2.svg
  49. BIN
      src/assets/images/page-enviroment/co2MapTop.png
  50. 3 0
      src/assets/images/page-enviroment/curtain.svg
  51. 37 0
      src/assets/images/page-enviroment/curtainTemp.svg
  52. 3 0
      src/assets/images/page-enviroment/humidification.svg
  53. 9 0
      src/assets/images/page-enviroment/jiaquan.svg
  54. 3 0
      src/assets/images/page-enviroment/lamp.svg
  55. 8 0
      src/assets/images/page-enviroment/lampMapTop.svg
  56. 76 0
      src/assets/images/page-enviroment/lampTemp.svg
  57. BIN
      src/assets/images/page-enviroment/maptemp1.png
  58. BIN
      src/assets/images/page-enviroment/maptemp11.png
  59. BIN
      src/assets/images/page-enviroment/maptemp2.png
  60. BIN
      src/assets/images/page-enviroment/maptemp22.png
  61. BIN
      src/assets/images/page-enviroment/maptemp3.png
  62. BIN
      src/assets/images/page-enviroment/maptemp33.png
  63. BIN
      src/assets/images/page-enviroment/maptemp4.png
  64. BIN
      src/assets/images/page-enviroment/maptemp44.png
  65. BIN
      src/assets/images/page-enviroment/maptemp5.png
  66. BIN
      src/assets/images/page-enviroment/maptemp55.png
  67. BIN
      src/assets/images/page-enviroment/maptemp6.png
  68. BIN
      src/assets/images/page-enviroment/maptemp66.png
  69. 9 0
      src/assets/images/page-enviroment/office.svg
  70. 8 0
      src/assets/images/page-enviroment/pm25.svg
  71. BIN
      src/assets/images/page-enviroment/temperMapTop.png
  72. 3 0
      src/assets/images/page-enviroment/temperature.svg
  73. 5 0
      src/assets/images/page-enviroment/tvoc.svg
  74. 4 0
      src/assets/images/page-enviroment/water.svg
  75. 52 0
      src/assets/images/page-enviroment/waterTemp.svg
  76. 3 0
      src/assets/images/page-enviroment/wet.svg
  77. 16 0
      src/components/PageHeader/index.jsx
  78. 18 0
      src/components/PageHeader/index.less
  79. 1 0
      src/config/api.js
  80. 34 0
      src/config/image.js
  81. 45 0
      src/e2e/baseLayout.e2e.spec.ts
  82. 60 0
      src/global.less
  83. 91 0
      src/global.tsx
  84. 16 0
      src/hooks/useMenuList.js
  85. 13 0
      src/layouts/index.jsx
  86. 15 0
      src/layouts/index.less
  87. 13 0
      src/locales/en-US.ts
  88. 5 0
      src/locales/en-US/component.ts
  89. 17 0
      src/locales/en-US/globalHeader.ts
  90. 52 0
      src/locales/en-US/menu.ts
  91. 70 0
      src/locales/en-US/pages.ts
  92. 60 0
      src/locales/en-US/settings.ts
  93. 13 0
      src/locales/zh-CN.ts
  94. 5 0
      src/locales/zh-CN/component.ts
  95. 17 0
      src/locales/zh-CN/globalHeader.ts
  96. 55 0
      src/locales/zh-CN/menu.ts
  97. 67 0
      src/locales/zh-CN/pages.ts
  98. 55 0
      src/locales/zh-CN/settings.ts
  99. 22 0
      src/manifest.json
  100. 0 0
      src/models/global.js

+ 16 - 0
.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

+ 8 - 0
.eslintignore

@@ -0,0 +1,8 @@
+/lambda/
+/scripts
+/config
+.history
+public
+dist
+.umi
+mock

+ 8 - 0
.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,
+  },
+};

+ 40 - 0
.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

+ 23 - 0
.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

+ 5 - 0
.prettierrc.js

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

+ 5 - 0
.stylelintrc.js

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

+ 8 - 0
.vscode/extensions.json

@@ -0,0 +1,8 @@
+{
+  "recommendations": [
+    "esbenp.prettier-vscode",
+    "dbaeumer.vscode-eslint",
+    "stylelint.vscode-stylelint",
+    "wangzy.sneak-mark"
+  ]
+}

+ 5 - 0
.vscode/settings.json

@@ -0,0 +1,5 @@
+{
+  "editor.formatOnSave": true,
+  "prettier.requireConfig": true,
+  "editor.defaultFormatter": "esbenp.prettier-vscode"
+}

+ 57 - 0
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).

+ 15 - 0
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: {},
+  },
+});

+ 73 - 0
config/config.ts

@@ -0,0 +1,73 @@
+// 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,
+  //   },
+  layout: false,
+  // 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,
+  // Theme for antd: https://ant.design/docs/react/customize-theme-cn
+  theme: {
+    '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: {},
+});

+ 21 - 0
config/defaultSettings.ts

@@ -0,0 +1,21 @@
+import { Settings as LayoutSettings } from '@ant-design/pro-layout';
+
+const Settings: LayoutSettings & {
+  pwa?: boolean;
+  logo?: string;
+} = {
+  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;

+ 593 - 0
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"
+          }
+        }
+      }
+    }
+  }
+}

+ 34 - 0
config/proxy.ts

@@ -0,0 +1,34 @@
+/**
+ * 在生产环境 代理是无法生效的,所以这里没有生产环境的配置
+ * -------------------------------
+ * 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: { '^': '' },
+    },
+  },
+};

+ 46 - 0
config/routes.ts

@@ -0,0 +1,46 @@
+export default [
+  {
+    path: '/user',
+    layout: false,
+    routes: [
+      {
+        path: '/user',
+        routes: [
+          {
+            name: 'login',
+            path: '/user/login',
+            component: './user/Login',
+          },
+        ],
+      },
+      {
+        component: './404',
+      },
+    ],
+  },
+  {
+    path: '/',
+    component: '../layouts',
+    routes: [
+      //   {
+      //     path: '/',
+      //     redirect: '/environment',
+      //   },
+      {
+        path: '/environment',
+        name: 'environment',
+        component: './Environment',
+      },
+      {
+        path: '/equipment',
+        name: 'equipment',
+        component: './Equipment',
+      },
+      {
+        path: '/runtime',
+        name: 'runtime',
+        component: './Runtime',
+      },
+    ],
+  },
+];

+ 9 - 0
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,
+  },
+};

+ 11 - 0
jsconfig.json

@@ -0,0 +1,11 @@
+{
+  "compilerOptions": {
+    "jsx": "react-jsx",
+    "emitDecoratorMetadata": true,
+    "experimentalDecorators": true,
+    "baseUrl": ".",
+    "paths": {
+      "@/*": ["./src/*"]
+    }
+  }
+}

+ 174 - 0
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,
+};

+ 107 - 0
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,
+};

+ 5 - 0
mock/route.ts

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

+ 203 - 0
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: '海纳百川,有容乃大2222',
+        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,
+};

+ 114 - 0
package.json

@@ -0,0 +1,114 @@
+{
+  "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",
+    "precommit": "lint-staged",
+    "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.3.5",
+    "@ant-design/icons": "^4.7.0",
+    "@ant-design/pro-descriptions": "^1.10.0",
+    "@ant-design/pro-form": "^1.52.0",
+    "@ant-design/pro-layout": "^6.32.0",
+    "@ant-design/pro-table": "^2.61.0",
+    "@umijs/route-utils": "^2.0.0",
+    "ahooks": "^3.1.9",
+    "antd": "^4.17.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": "^1.8.17",
+    "@umijs/yorkie": "^2.0.5",
+    "carlo": "^0.9.46",
+    "cross-env": "^7.0.0",
+    "cross-port-killer": "^1.3.0",
+    "detect-installer": "^1.0.0",
+    "enzyme": "^3.11.0",
+    "eslint": "^7.32.0",
+    "express": "^4.17.0",
+    "gh-pages": "^3.2.0",
+    "jsdom-global": "^3.0.0",
+    "lint-staged": "^10.0.0",
+    "mockjs": "^1.1.0",
+    "prettier": "^2.5.0",
+    "puppeteer-core": "^8.0.0",
+    "stylelint": "^13.0.0",
+    "swagger-ui-react": "^3.52.0",
+    "typescript": "^4.5.0",
+    "umi-serve": "^1.9.10"
+  },
+  "engines": {
+    "node": ">=10.0.0"
+  },
+  "gitHooks": {
+    "commit-msg": "fabric verify-commit"
+  }
+}

+ 22 - 0
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;

+ 1 - 0
public/CNAME

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

BIN
public/favicon.ico


BIN
public/icons/icon-128x128.png


BIN
public/icons/icon-192x192.png


BIN
public/icons/icon-512x512.png


ファイルの差分が大きいため隠しています
+ 1 - 0
public/logo.svg


ファイルの差分が大きいため隠しています
+ 5 - 0
public/pro_icon.svg


+ 9 - 0
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',
+  };
+}

+ 86 - 0
src/antd-reset.less

@@ -0,0 +1,86 @@
+.ten {
+  .ant-modal-confirm-confirm {
+    width: 360px !important;
+    .ant-modal-content {
+      background: #fff;
+      border-radius: 20px;
+    }
+    .ant-modal-confirm-body > .anticon {
+      display: none;
+    }
+    .ant-modal-confirm-body > .anticon + .ant-modal-confirm-title + .ant-modal-confirm-content {
+      margin: 20px auto;
+      font-size: 16px;
+    }
+    .ant-modal-confirm-btns {
+      float: none;
+      margin-top: 50px;
+      text-align: center;
+    }
+  }
+
+  .ant-select-dropdown {
+    padding: 0;
+    border-radius: 10px;
+  }
+  .ant-select-item {
+    line-height: 34px;
+    border-bottom: 1px solid #f7f7f7;
+    &:first-child {
+      border-radius: 10px 10px 0 0;
+    }
+    &:last-child {
+      border-bottom: none;
+      border-radius: 0 0 10px 10px 0;
+    }
+  }
+  .ant-select-item-option:not(.ant-select-item-option-disabled) {
+    color: #000;
+    &:hover {
+      background: @primary-color;
+    }
+  }
+  .ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
+    background: @primary-color;
+  }
+
+  .ant-modal-content {
+    background: transparent;
+    box-shadow: none;
+  }
+  .ant-modal-body {
+    padding: 0;
+    background: transparent;
+    border-radius: 20px;
+  }
+
+  .ant-select-single.ant-select-lg:not(.ant-select-customize-input) .ant-select-selector {
+    height: 50px;
+    &:hover {
+      color: #000;
+    }
+  }
+  .ant-select:not(.ant-select-customize-input) .ant-select-selector {
+    border: 1px solid #c4c4c4;
+  }
+  .ant-select:not(.ant-select-disabled):hover .ant-select-selector {
+    border: 1px solid #9c9c9c;
+  }
+  .ant-select-focused:not(.ant-select-disabled).ant-select:not(.ant-select-customize-input)
+    .ant-select-selector {
+    border: 1px solid #9c9c9c;
+    box-shadow: none;
+  }
+  .ant-select-single.ant-select-lg:not(.ant-select-customize-input) .ant-select-selector::after,
+  .ant-select-single.ant-select-lg:not(.ant-select-customize-input)
+    .ant-select-selector
+    .ant-select-selection-item,
+  .ant-select-single.ant-select-lg:not(.ant-select-customize-input)
+    .ant-select-selector
+    .ant-select-selection-placeholder {
+    line-height: 48px;
+  }
+  .ant-select {
+    color: #4f5055;
+  }
+}

+ 26 - 0
src/antd-tenants.less

@@ -0,0 +1,26 @@
+@font-variant-base: none;
+@font-feature-settings-base: normal;
+
+@body-background: #eef1f2;
+
+@primary-color: #f0da21;
+@text-color: #4D5262;
+
+@height-lg: 50px;
+
+// @btn-text-hover-bg: #fff;
+@btn-primary-color: #000;
+@btn-primary-bg: #FFE823;
+@btn-primary-shadow: 0px 4px 6px rgba(0, 0, 0, 0.07), 0px 0px 1px rgba(0, 0, 0, 0.15);
+@btn-font-size-lg: 14px;
+@btn-padding-horizontal-lg: 30px;
+@btn-border-radius-base: 30px;
+@btn-text-shadow: none;
+@btn-default-hover-bg: rgba(196, 196, 196, 0.2);
+
+@table-bg: transparent;
+@table-header-bg: transparent;
+@table-padding-vertical: 8px;
+@table-header-cell-split-color: transparent;
+
+@popover-arrow-width: 0px;

+ 103 - 0
src/app.tsx

@@ -0,0 +1,103 @@
+import type { Settings as LayoutSettings } from '@ant-design/pro-layout';
+import { PageLoading } from '@ant-design/pro-layout';
+import { history } from 'umi';
+import { currentUser as queryCurrentUser } from './services/ant-design-pro/api';
+import defaultSettings from '../config/defaultSettings';
+
+const loginPath = '/user/login';
+
+/** 获取用户信息比较慢的时候会展示一个 loading */
+export const initialStateConfig = {
+  loading: <PageLoading />,
+};
+
+/**
+ * @see  https://umijs.org/zh-CN/plugins/plugin-initial-state
+ * */
+export async function getInitialState(): Promise<{
+  settings?: Partial<LayoutSettings>;
+  currentUser?: API.CurrentUser;
+  loading?: boolean;
+  fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
+}> {
+  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: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
+//   return {
+//     rightContentRender: () => <RightContent />,
+//     disableContentMargin: false,
+//     waterMarkProps: {
+//       content: initialState?.currentUser?.name,
+//     },
+//     footerRender: () => <Footer />,
+//     onPageChange: () => {
+//       const { location } = history;
+//       // 如果没有登录,重定向到 login
+//       if (!initialState?.currentUser && location.pathname !== loginPath) {
+//         history.push(loginPath);
+//       }
+//     },
+//     links: isDev
+//       ? [
+//           <Link to="/umi/plugin/openapi" target="_blank">
+//             <LinkOutlined />
+//             <span>OpenAPI 文档</span>
+//           </Link>,
+//           <Link to="/~docs">
+//             <BookOutlined />
+//             <span>业务组件文档</span>
+//           </Link>,
+//         ]
+//       : [],
+//     menuHeaderRender: undefined,
+//     // 自定义 403 页面
+//     // unAccessible: <div>unAccessible</div>,
+//     // 增加一个 loading 的状态
+//     childrenRender: (children, props) => {
+//       // if (initialState?.loading) return <PageLoading />;
+//       return (
+//         <>
+//           {children}
+//           {!props.location?.pathname?.includes('/login') && (
+//             <SettingDrawer
+//               enableDarkTheme
+//               settings={initialState?.settings}
+//               onSettingChange={(settings) => {
+//                 setInitialState((preInitialState) => ({
+//                   ...preInitialState,
+//                   settings,
+//                 }));
+//               }}
+//             />
+//           )}
+//         </>
+//       );
+//     },
+//     ...initialState?.settings,
+//   };
+// };

BIN
src/assets/fonts/Montserrat-Regular.woff2


ファイルの差分が大きいため隠しています
+ 68 - 0
src/assets/images/empty-apply.svg


ファイルの差分が大きいため隠しています
+ 52 - 0
src/assets/images/empty.svg


+ 11 - 0
src/assets/images/message-error.svg

@@ -0,0 +1,11 @@
+<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
+<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="60" height="60">
+<circle cx="30" cy="30" r="30" fill="#F0DA21"/>
+</mask>
+<g mask="url(#mask0)">
+<circle cx="30" cy="30" r="30" fill="white"/>
+<circle cx="30" cy="30" r="22" fill="#FF4D5E"/>
+<circle cx="30" cy="41" r="3" fill="white"/>
+<path d="M28.0317 17.9997C28.0143 16.9005 28.9006 16 30 16C31.0994 16 31.9857 16.9005 31.9683 17.9997L31.7415 32.2859C31.7264 33.237 30.9511 34 30 34C29.0489 34 28.2736 33.237 28.2585 32.2859L28.0317 17.9997Z" fill="white"/>
+</g>
+</svg>

+ 11 - 0
src/assets/images/message-info.svg

@@ -0,0 +1,11 @@
+<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
+<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="60" height="60">
+<circle cx="30" cy="30" r="30" fill="#F0DA21"/>
+</mask>
+<g mask="url(#mask0)">
+<circle cx="30" cy="30" r="30" fill="white"/>
+<circle cx="30" cy="30" r="22" fill="#F0DA21"/>
+<circle cx="30" cy="23" r="4" fill="white"/>
+<path d="M27 36C27 34.3431 28.3431 33 30 33C31.6569 33 33 34.3431 33 36V57C33 58.6569 31.6569 60 30 60C28.3431 60 27 58.6569 27 57V36Z" fill="white"/>
+</g>
+</svg>

+ 10 - 0
src/assets/images/message-success.svg

@@ -0,0 +1,10 @@
+<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
+<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="60" height="60">
+<circle cx="30" cy="30" r="30" fill="#F0DA21"/>
+</mask>
+<g mask="url(#mask0)">
+<circle cx="30" cy="30" r="30" fill="white"/>
+<circle cx="30" cy="30" r="22" fill="#07C160"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M53.3117 10.4902C54.1455 11.2147 54.2342 12.4779 53.5098 13.3117L30.9216 39.3117C30.5593 39.7287 30.0406 39.9773 29.4886 39.9986C28.9366 40.0198 28.4004 39.8117 28.0071 39.4237L18.5954 30.138C17.8091 29.3623 17.8005 28.096 18.5763 27.3097C19.3521 26.5234 20.6184 26.5148 21.4046 27.2906L29.2995 35.0797L50.4902 10.6883C51.2146 9.85451 52.4778 9.76581 53.3117 10.4902Z" fill="white"/>
+</g>
+</svg>

ファイルの差分が大きいため隠しています
+ 3 - 0
src/assets/images/page-enviroment/air.svg


ファイルの差分が大きいため隠しています
+ 8 - 0
src/assets/images/page-enviroment/airMapTop.svg


ファイルの差分が大きいため隠しています
+ 73 - 0
src/assets/images/page-enviroment/airTemp.svg


ファイルの差分が大きいため隠しています
+ 3 - 0
src/assets/images/page-enviroment/all.svg


BIN
src/assets/images/page-enviroment/chartTemp.png


ファイルの差分が大きいため隠しています
+ 3 - 0
src/assets/images/page-enviroment/close.svg


ファイルの差分が大きいため隠しています
+ 4 - 0
src/assets/images/page-enviroment/co2.svg


BIN
src/assets/images/page-enviroment/co2MapTop.png


ファイルの差分が大きいため隠しています
+ 3 - 0
src/assets/images/page-enviroment/curtain.svg


ファイルの差分が大きいため隠しています
+ 37 - 0
src/assets/images/page-enviroment/curtainTemp.svg


ファイルの差分が大きいため隠しています
+ 3 - 0
src/assets/images/page-enviroment/humidification.svg


ファイルの差分が大きいため隠しています
+ 9 - 0
src/assets/images/page-enviroment/jiaquan.svg


ファイルの差分が大きいため隠しています
+ 3 - 0
src/assets/images/page-enviroment/lamp.svg


ファイルの差分が大きいため隠しています
+ 8 - 0
src/assets/images/page-enviroment/lampMapTop.svg


ファイルの差分が大きいため隠しています
+ 76 - 0
src/assets/images/page-enviroment/lampTemp.svg


BIN
src/assets/images/page-enviroment/maptemp1.png


BIN
src/assets/images/page-enviroment/maptemp11.png


BIN
src/assets/images/page-enviroment/maptemp2.png


BIN
src/assets/images/page-enviroment/maptemp22.png


BIN
src/assets/images/page-enviroment/maptemp3.png


BIN
src/assets/images/page-enviroment/maptemp33.png


BIN
src/assets/images/page-enviroment/maptemp4.png


BIN
src/assets/images/page-enviroment/maptemp44.png


BIN
src/assets/images/page-enviroment/maptemp5.png


BIN
src/assets/images/page-enviroment/maptemp55.png


BIN
src/assets/images/page-enviroment/maptemp6.png


BIN
src/assets/images/page-enviroment/maptemp66.png


+ 9 - 0
src/assets/images/page-enviroment/office.svg

@@ -0,0 +1,9 @@
+<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M26.4483 18.375H1.35327C0.874938 18.375 0.478271 17.9783 0.478271 17.5C0.478271 17.0217 0.874938 16.625 1.35327 16.625H26.4483C26.9266 16.625 27.3233 17.0217 27.3233 17.5C27.3233 17.9783 26.9266 18.375 26.4483 18.375Z" fill="#140050"/>
+<path d="M24.395 22.4117H3.3833C2.90497 22.4117 2.5083 22.015 2.5083 21.5367C2.5083 21.0583 2.90497 20.6617 3.3833 20.6617H24.395C24.8733 20.6617 25.27 21.0583 25.27 21.5367C25.27 22.015 24.885 22.4117 24.395 22.4117Z" fill="#140050"/>
+<path d="M4.31665 14.875C3.82665 14.875 3.44165 14.4783 3.44165 14V9.74167C3.44165 9.26334 3.83832 8.86667 4.31665 8.86667C4.79498 8.86667 5.19165 9.26334 5.19165 9.74167V14C5.19165 14.4783 4.79498 14.875 4.31665 14.875Z" fill="#140050"/>
+<path d="M7.57153 14.875C7.0932 14.875 6.69653 14.4783 6.69653 14V11.1883C6.69653 10.71 7.0932 10.3133 7.57153 10.3133C8.04987 10.3133 8.44653 10.71 8.44653 11.1883V14C8.44653 14.4783 8.04987 14.875 7.57153 14.875Z" fill="#140050"/>
+<path d="M2.15821 27.7083C2.08821 27.7083 2.02987 27.6967 1.95987 27.685C1.4932 27.58 1.18987 27.1017 1.30654 26.635L3.46487 17.3017C3.56987 16.835 4.0482 16.5317 4.51487 16.6483C4.98153 16.7533 5.28487 17.2317 5.1682 17.6983L3.00987 27.0317C2.91654 27.44 2.55487 27.7083 2.15821 27.7083Z" fill="#140050"/>
+<path d="M25.8532 27.7083C25.4565 27.7083 25.0948 27.44 25.0015 27.0317L22.8432 17.6983C22.7382 17.2317 23.0298 16.7533 23.4965 16.6483C23.9632 16.5317 24.4415 16.835 24.5465 17.3017L26.7048 26.635C26.8098 27.1017 26.5182 27.58 26.0515 27.685C25.9815 27.6967 25.9115 27.7083 25.8532 27.7083Z" fill="#140050"/>
+<path d="M22.6216 14.875H11.8533C11.3749 14.875 10.9783 14.4783 10.9783 14V7C10.9783 6.52167 11.3749 6.125 11.8533 6.125H22.6216C23.0999 6.125 23.4966 6.52167 23.4966 7V14C23.4966 14.4783 23.0999 14.875 22.6216 14.875ZM12.7283 13.125H21.7466V7.875H12.7283V13.125Z" fill="#140050"/>
+</svg>

ファイルの差分が大きいため隠しています
+ 8 - 0
src/assets/images/page-enviroment/pm25.svg


BIN
src/assets/images/page-enviroment/temperMapTop.png


ファイルの差分が大きいため隠しています
+ 3 - 0
src/assets/images/page-enviroment/temperature.svg


+ 5 - 0
src/assets/images/page-enviroment/tvoc.svg

@@ -0,0 +1,5 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.66675 2.29175C4.2505 2.29175 2.29175 4.2505 2.29175 6.66675C2.29175 9.08299 4.2505 11.0417 6.66675 11.0417C9.08299 11.0417 11.0417 9.08299 11.0417 6.66675C11.0417 4.2505 9.08299 2.29175 6.66675 2.29175ZM1.04175 6.66675C1.04175 3.56015 3.56015 1.04175 6.66675 1.04175C9.77335 1.04175 12.2917 3.56015 12.2917 6.66675C12.2917 9.77335 9.77335 12.2917 6.66675 12.2917C3.56015 12.2917 1.04175 9.77335 1.04175 6.66675Z" fill="#2D553E"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M15.0001 12.2917C13.5043 12.2917 12.2917 13.5043 12.2917 15.0001C12.2917 16.4959 13.5043 17.7084 15.0001 17.7084C16.4959 17.7084 17.7084 16.4959 17.7084 15.0001C17.7084 13.5043 16.4959 12.2917 15.0001 12.2917ZM11.0417 15.0001C11.0417 12.814 12.814 11.0417 15.0001 11.0417C17.1862 11.0417 18.9584 12.814 18.9584 15.0001C18.9584 17.1862 17.1862 18.9584 15.0001 18.9584C12.814 18.9584 11.0417 17.1862 11.0417 15.0001Z" fill="#2D553E"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M16.6667 4.79175C16.0914 4.79175 15.625 5.25812 15.625 5.83341C15.625 6.40871 16.0914 6.87508 16.6667 6.87508C17.242 6.87508 17.7083 6.40871 17.7083 5.83341C17.7083 5.25812 17.242 4.79175 16.6667 4.79175ZM14.375 5.83341C14.375 4.56776 15.401 3.54175 16.6667 3.54175C17.9323 3.54175 18.9583 4.56776 18.9583 5.83341C18.9583 7.09907 17.9323 8.12508 16.6667 8.12508C15.401 8.12508 14.375 7.09907 14.375 5.83341Z" fill="#2D553E"/>
+</svg>

ファイルの差分が大きいため隠しています
+ 4 - 0
src/assets/images/page-enviroment/water.svg


ファイルの差分が大きいため隠しています
+ 52 - 0
src/assets/images/page-enviroment/waterTemp.svg


ファイルの差分が大きいため隠しています
+ 3 - 0
src/assets/images/page-enviroment/wet.svg


+ 16 - 0
src/components/PageHeader/index.jsx

@@ -0,0 +1,16 @@
+import React from 'react';
+import styles from './index.less';
+
+export default ({
+  title,
+  action,
+}) => {
+  return (
+    <div className={styles.c}>
+      <div className={styles.title}>{ title }</div>
+      {
+        action
+      }
+    </div>
+  )
+}

+ 18 - 0
src/components/PageHeader/index.less

@@ -0,0 +1,18 @@
+.c {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.title {
+  font-size: 24px;
+  color: #000;
+  font-weight: 600;
+  &::before {
+    content: "/";
+    font-size: 32px;
+    font-weight: normal;
+    color: #f0da21;
+    margin-right: 10px;
+  }
+}

+ 1 - 0
src/config/api.js

@@ -0,0 +1 @@
+export const BASE_PATH = '/api';

+ 34 - 0
src/config/image.js

@@ -0,0 +1,34 @@
+export const equipImageMap = {
+  chartTemp: require('@/assets/images/page-enviroment/chartTemp.png'),
+  temperMapTop: require('@/assets/images/page-enviroment/temperMapTop.png'),
+  co2MapTop: require('@/assets/images/page-enviroment/co2MapTop.png'),
+  maptemp1: require('@/assets/images/page-enviroment/maptemp1.png'),
+  maptemp2: require('@/assets/images/page-enviroment/maptemp2.png'),
+  envir_temperature: require('@/assets/images/page-enviroment/temperature.svg'),
+  envir_wet: require('@/assets/images/page-enviroment/wet.svg'),
+  envir_co2: require('@/assets/images/page-enviroment/co2.svg'),
+  envir_pm25: require('@/assets/images/page-enviroment/pm25.svg'),
+  envir_jiaquan: require('@/assets/images/page-enviroment/jiaquan.svg'),
+  envir_tvoc: require('@/assets/images/page-enviroment/tvoc.svg'),
+
+  officeImg: require('@/assets/images/page-enviroment/office.svg'),
+  curtainTemp: require('@/assets/images/page-enviroment/curtainTemp.svg'),
+  waterTemp: require('@/assets/images/page-enviroment/waterTemp.svg'),
+  lampTemp: require('@/assets/images/page-enviroment/lampTemp.svg'),
+  airTemp: require('@/assets/images/page-enviroment/airTemp.svg'),
+
+  airMapTop: require('@/assets/images/page-enviroment/airMapTop.svg'),
+  lampMapTop: require('@/assets/images/page-enviroment/lampMapTop.svg'),
+  maptemp3: require('@/assets/images/page-enviroment/maptemp3.png'),
+  maptemp4: require('@/assets/images/page-enviroment/maptemp4.png'),
+  maptemp5: require('@/assets/images/page-enviroment/maptemp5.png'),
+
+  envir_all: require('@/assets/images/page-enviroment/all.svg'),
+  equip_air: require('@/assets/images/page-enviroment/air.svg'),
+  equip_lamp: require('@/assets/images/page-enviroment/lamp.svg'),
+  equip_water: require('@/assets/images/page-enviroment/water.svg'),
+  envir_curtain: require('@/assets/images/page-enviroment/curtain.svg'),
+  envir_humidification: require('@/assets/images/page-enviroment/humidification.svg'),
+
+  maptemp6: require('@/assets/images/page-enviroment/maptemp6.png'),
+};

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

@@ -0,0 +1,45 @@
+import type { Page } from '@playwright/test';
+import { test, expect } from '@playwright/test';
+const { uniq } = require('lodash');
+const RouterConfig = require('../../config/routes').default;
+
+const BASE_URL = `http://localhost:${process.env.PORT || 8001}`;
+
+function formatter(routes: any, parentPath = ''): string[] {
+  const fixedParentPath = parentPath.replace(/\/{1,}/g, '/');
+  let result: string[] = [];
+  routes.forEach((item: { path: string; routes: string }) => {
+    if (item.path && !item.path.startsWith('/')) {
+      result.push(`${fixedParentPath}/${item.path}`.replace(/\/{1,}/g, '/'));
+    }
+    if (item.path && item.path.startsWith('/')) {
+      result.push(`${item.path}`.replace(/\/{1,}/g, '/'));
+    }
+    if (item.routes) {
+      result = result.concat(
+        formatter(item.routes, item.path ? `${fixedParentPath}/${item.path}` : parentPath),
+      );
+    }
+  });
+  return uniq(result.filter((item) => !!item));
+}
+
+const testPage = (path: string, page: Page) => async () => {
+  await page.evaluate(() => {
+    localStorage.setItem('antd-pro-authority', '["admin"]');
+  });
+  await page.goto(`${BASE_URL}${path}`);
+  await page.waitForSelector('footer', {
+    timeout: 2000,
+  });
+  const haveFooter = await page.evaluate(() => document.getElementsByTagName('footer').length > 0);
+  expect(haveFooter).toBeTruthy();
+};
+
+const routers = formatter(RouterConfig);
+
+routers.forEach((route) => {
+  test(`test route page ${route}`, async ({ page }) => {
+    await testPage(route, page);
+  });
+});

+ 60 - 0
src/global.less

@@ -0,0 +1,60 @@
+@import '~antd/es/style/variable.less';
+@import '~antd/dist/antd.less'; // 引入官方提供的 less 样式入口文件
+@import './antd-tenants.less';
+@import './antd-reset.less';
+
+html,
+body,
+#root {
+  height: 100%;
+}
+
+.colorWeak {
+  filter: invert(80%);
+}
+
+.ant-layout {
+  min-height: 100vh;
+}
+.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
+  left: unset;
+}
+
+canvas {
+  display: block;
+}
+
+body {
+  text-rendering: optimizeLegibility;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+ul,
+ol {
+  list-style: none;
+}
+
+@media (max-width: @screen-xs) {
+  .ant-table {
+    width: 100%;
+    overflow-x: auto;
+    &-thead > tr,
+    &-tbody > tr {
+      > th,
+      > td {
+        white-space: pre;
+        > span {
+          display: block;
+        }
+      }
+    }
+  }
+}
+
+// Compatible with IE11
+@media screen and(-ms-high-contrast: active), (-ms-high-contrast: none) {
+  body .ant-design-pro > .ant-layout {
+    min-height: 100vh;
+  }
+}

+ 91 - 0
src/global.tsx

@@ -0,0 +1,91 @@
+import { Button, message, notification } from 'antd';
+import { useIntl } from 'umi';
+import defaultSettings from '../config/defaultSettings';
+
+const { pwa } = defaultSettings;
+const isHttps = document.location.protocol === 'https:';
+
+const clearCache = () => {
+  // remove all caches
+  if (window.caches) {
+    caches
+      .keys()
+      .then((keys) => {
+        keys.forEach((key) => {
+          caches.delete(key);
+        });
+      })
+      .catch((e) => console.log(e));
+  }
+};
+
+// if pwa is true
+if (pwa) {
+  // Notify user if offline now
+  window.addEventListener('sw.offline', () => {
+    message.warning(useIntl().formatMessage({ id: 'app.pwa.offline' }));
+  });
+
+  // Pop up a prompt on the page asking the user if they want to use the latest version
+  window.addEventListener('sw.updated', (event: Event) => {
+    const e = event as CustomEvent;
+    const reloadSW = async () => {
+      // Check if there is sw whose state is waiting in ServiceWorkerRegistration
+      // https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration
+      const worker = e.detail && e.detail.waiting;
+      if (!worker) {
+        return true;
+      }
+      // Send skip-waiting event to waiting SW with MessageChannel
+      await new Promise((resolve, reject) => {
+        const channel = new MessageChannel();
+        channel.port1.onmessage = (msgEvent) => {
+          if (msgEvent.data.error) {
+            reject(msgEvent.data.error);
+          } else {
+            resolve(msgEvent.data);
+          }
+        };
+        worker.postMessage({ type: 'skip-waiting' }, [channel.port2]);
+      });
+
+      clearCache();
+      window.location.reload();
+      return true;
+    };
+    const key = `open${Date.now()}`;
+    const btn = (
+      <Button
+        type="primary"
+        onClick={() => {
+          notification.close(key);
+          reloadSW();
+        }}
+      >
+        {useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.ok' })}
+      </Button>
+    );
+    notification.open({
+      message: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated' }),
+      description: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }),
+      btn,
+      key,
+      onClose: async () => null,
+    });
+  });
+} else if ('serviceWorker' in navigator && isHttps) {
+  // unregister service worker
+  const { serviceWorker } = navigator;
+  if (serviceWorker.getRegistrations) {
+    serviceWorker.getRegistrations().then((sws) => {
+      sws.forEach((sw) => {
+        sw.unregister();
+      });
+    });
+  }
+  serviceWorker.getRegistration().then((sw) => {
+    if (sw) sw.unregister();
+  });
+
+  clearCache();
+}

+ 16 - 0
src/hooks/useMenuList.js

@@ -0,0 +1,16 @@
+import { useState, useEffect } from 'react';
+import { getPanelMenu } from '../services';
+
+export default function useMenuList() {
+  const [list, setList] = useState([]);
+  useEffect(() => {
+    getPanelMenu().then((res) => {
+      if (res.code === 1) {
+        setList(res.data);
+      }
+    });
+  }, []);
+  return {
+    list,
+  };
+}

+ 13 - 0
src/layouts/index.jsx

@@ -0,0 +1,13 @@
+import React, { useEffect } from 'react';
+import { useModel, useLocation, useIntl } from 'umi';
+import styles from './index.less';
+
+export default (props) => {
+  return (
+    <>
+      <div className={styles.layout}>
+        <div className={styles.content}>{props.children}</div>
+      </div>
+    </>
+  );
+};

+ 15 - 0
src/layouts/index.less

@@ -0,0 +1,15 @@
+.layout {
+  width: 1340px;
+  margin: 0 auto;
+}
+
+.header {
+  padding: 42px 0 35px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.footer {
+  padding-top: 80px;
+}

+ 13 - 0
src/locales/en-US.ts

@@ -0,0 +1,13 @@
+import component from './zh-CN/component';
+import globalHeader from './zh-CN/globalHeader';
+import menu from './zh-CN/menu';
+import settings from './zh-CN/settings';
+import pages from './zh-CN/pages';
+
+export default {
+  ...pages,
+  ...globalHeader,
+  ...menu,
+  ...settings,
+  ...component,
+};

+ 5 - 0
src/locales/en-US/component.ts

@@ -0,0 +1,5 @@
+export default {
+  'component.tagSelect.expand': 'Expand',
+  'component.tagSelect.collapse': 'Collapse',
+  'component.tagSelect.all': 'All',
+};

+ 17 - 0
src/locales/en-US/globalHeader.ts

@@ -0,0 +1,17 @@
+export default {
+  'component.globalHeader.search': 'Search',
+  'component.globalHeader.search.example1': 'Search example 1',
+  'component.globalHeader.search.example2': 'Search example 2',
+  'component.globalHeader.search.example3': 'Search example 3',
+  'component.globalHeader.help': 'Help',
+  'component.globalHeader.notification': 'Notification',
+  'component.globalHeader.notification.empty': 'You have viewed all notifications.',
+  'component.globalHeader.message': 'Message',
+  'component.globalHeader.message.empty': 'You have viewed all messsages.',
+  'component.globalHeader.event': 'Event',
+  'component.globalHeader.event.empty': 'You have viewed all events.',
+  'component.noticeIcon.clear': 'Clear',
+  'component.noticeIcon.cleared': 'Cleared',
+  'component.noticeIcon.empty': 'No notifications',
+  'component.noticeIcon.view-more': 'View more',
+};

+ 52 - 0
src/locales/en-US/menu.ts

@@ -0,0 +1,52 @@
+export default {
+  'menu.welcome': 'Welcome',
+  'menu.more-blocks': 'More Blocks',
+  'menu.home': 'Home',
+  'menu.admin': 'Admin',
+  'menu.admin.sub-page': 'Sub-Page',
+  'menu.login': 'Login',
+  'menu.register': 'Register',
+  'menu.register-result': 'Register Result',
+  'menu.dashboard': 'Dashboard',
+  'menu.dashboard.analysis': 'Analysis',
+  'menu.dashboard.monitor': 'Monitor',
+  'menu.dashboard.workplace': 'Workplace',
+  'menu.exception.403': '403',
+  'menu.exception.404': '404',
+  'menu.exception.500': '500',
+  'menu.form': 'Form',
+  'menu.form.basic-form': 'Basic Form',
+  'menu.form.step-form': 'Step Form',
+  'menu.form.step-form.info': 'Step Form(write transfer information)',
+  'menu.form.step-form.confirm': 'Step Form(confirm transfer information)',
+  'menu.form.step-form.result': 'Step Form(finished)',
+  'menu.form.advanced-form': 'Advanced Form',
+  'menu.list': 'List',
+  'menu.list.table-list': 'Search Table',
+  'menu.list.basic-list': 'Basic List',
+  'menu.list.card-list': 'Card List',
+  'menu.list.search-list': 'Search List',
+  'menu.list.search-list.articles': 'Search List(articles)',
+  'menu.list.search-list.projects': 'Search List(projects)',
+  'menu.list.search-list.applications': 'Search List(applications)',
+  'menu.profile': 'Profile',
+  'menu.profile.basic': 'Basic Profile',
+  'menu.profile.advanced': 'Advanced Profile',
+  'menu.result': 'Result',
+  'menu.result.success': 'Success',
+  'menu.result.fail': 'Fail',
+  'menu.exception': 'Exception',
+  'menu.exception.not-permission': '403',
+  'menu.exception.not-find': '404',
+  'menu.exception.server-error': '500',
+  'menu.exception.trigger': 'Trigger',
+  'menu.account': 'Account',
+  'menu.account.center': 'Account Center',
+  'menu.account.settings': 'Account Settings',
+  'menu.account.trigger': 'Trigger Error',
+  'menu.account.logout': 'Logout',
+  'menu.editor': 'Graphic Editor',
+  'menu.editor.flow': 'Flow Editor',
+  'menu.editor.mind': 'Mind Editor',
+  'menu.editor.koni': 'Koni Editor',
+};

+ 70 - 0
src/locales/en-US/pages.ts

@@ -0,0 +1,70 @@
+export default {
+  'pages.layouts.userLayout.title':
+    'Ant Design is the most influential web design specification in Xihu district',
+  'pages.login.accountLogin.tab': 'Account Login',
+  'pages.login.accountLogin.errorMessage': 'Incorrect username/password(admin/ant.design)',
+  'pages.login.failure': 'Login failed, please try again!',
+  'pages.login.success': 'Login successful!',
+  'pages.login.username.placeholder': 'Username: admin or user',
+  'pages.login.username.required': 'Please input your username!',
+  'pages.login.password.placeholder': 'Password: ant.design',
+  'pages.login.password.required': 'Please input your password!',
+  'pages.login.phoneLogin.tab': 'Phone Login',
+  'pages.login.phoneLogin.errorMessage': 'Verification Code Error',
+  'pages.login.phoneNumber.placeholder': 'Phone Number',
+  'pages.login.phoneNumber.required': 'Please input your phone number!',
+  'pages.login.phoneNumber.invalid': 'Phone number is invalid!',
+  'pages.login.captcha.placeholder': 'Verification Code',
+  'pages.login.captcha.required': 'Please input verification code!',
+  'pages.login.phoneLogin.getVerificationCode': 'Get Code',
+  'pages.getCaptchaSecondText': 'sec(s)',
+  'pages.login.rememberMe': 'Remember me',
+  'pages.login.forgotPassword': 'Forgot Password ?',
+  'pages.login.submit': 'Login',
+  'pages.login.loginWith': 'Login with :',
+  'pages.login.registerAccount': 'Register Account',
+  'pages.welcome.advancedComponent': 'Advanced Component',
+  'pages.welcome.link': 'Welcome',
+  'pages.welcome.advancedLayout': 'Advanced Layout',
+  'pages.welcome.alertMessage': 'Faster and stronger heavy-duty components have been released.',
+  'pages.admin.subPage.title': 'This page can only be viewed by Admin',
+  'pages.admin.subPage.alertMessage':
+    'Umi ui is now released, welcome to use npm run ui to start the experience.',
+  'pages.searchTable.createForm.newRule': 'New Rule',
+  'pages.searchTable.updateForm.ruleConfig': 'Rule configuration',
+  'pages.searchTable.updateForm.basicConfig': 'Basic Information',
+  'pages.searchTable.updateForm.ruleName.nameLabel': 'Rule Name',
+  'pages.searchTable.updateForm.ruleName.nameRules': 'Please enter the rule name!',
+  'pages.searchTable.updateForm.ruleDesc.descLabel': 'Rule Description',
+  'pages.searchTable.updateForm.ruleDesc.descPlaceholder': 'Please enter at least five characters',
+  'pages.searchTable.updateForm.ruleDesc.descRules':
+    'Please enter a rule description of at least five characters!',
+  'pages.searchTable.updateForm.ruleProps.title': 'Configure Properties',
+  'pages.searchTable.updateForm.object': 'Monitoring Object',
+  'pages.searchTable.updateForm.ruleProps.templateLabel': 'Rule Template',
+  'pages.searchTable.updateForm.ruleProps.typeLabel': 'Rule Type',
+  'pages.searchTable.updateForm.schedulingPeriod.title': 'Set Scheduling Period',
+  'pages.searchTable.updateForm.schedulingPeriod.timeLabel': 'Starting Time',
+  'pages.searchTable.updateForm.schedulingPeriod.timeRules': 'Please choose a start time!',
+  'pages.searchTable.titleDesc': 'Description',
+  'pages.searchTable.ruleName': 'Rule name is required',
+  'pages.searchTable.titleCallNo': 'Number of Service Calls',
+  'pages.searchTable.titleStatus': 'Status',
+  'pages.searchTable.nameStatus.default': 'default',
+  'pages.searchTable.nameStatus.running': 'running',
+  'pages.searchTable.nameStatus.online': 'online',
+  'pages.searchTable.nameStatus.abnormal': 'abnormal',
+  'pages.searchTable.titleUpdatedAt': 'Last Scheduled at',
+  'pages.searchTable.exception': 'Please enter the reason for the exception!',
+  'pages.searchTable.titleOption': 'Option',
+  'pages.searchTable.config': 'Configuration',
+  'pages.searchTable.subscribeAlert': 'Subscribe to alerts',
+  'pages.searchTable.title': 'Enquiry Form',
+  'pages.searchTable.new': 'New',
+  'pages.searchTable.chosen': 'chosen',
+  'pages.searchTable.item': 'item',
+  'pages.searchTable.totalServiceCalls': 'Total Number of Service Calls',
+  'pages.searchTable.tenThousand': '0000',
+  'pages.searchTable.batchDeletion': 'bacth deletion',
+  'pages.searchTable.batchApproval': 'batch approval',
+};

+ 60 - 0
src/locales/en-US/settings.ts

@@ -0,0 +1,60 @@
+export default {
+  'app.settings.menuMap.basic': 'Basic Settings',
+  'app.settings.menuMap.security': 'Security Settings',
+  'app.settings.menuMap.binding': 'Account Binding',
+  'app.settings.menuMap.notification': 'New Message Notification',
+  'app.settings.basic.avatar': 'Avatar',
+  'app.settings.basic.change-avatar': 'Change avatar',
+  'app.settings.basic.email': 'Email',
+  'app.settings.basic.email-message': 'Please input your email!',
+  'app.settings.basic.nickname': 'Nickname',
+  'app.settings.basic.nickname-message': 'Please input your Nickname!',
+  'app.settings.basic.profile': 'Personal profile',
+  'app.settings.basic.profile-message': 'Please input your personal profile!',
+  'app.settings.basic.profile-placeholder': 'Brief introduction to yourself',
+  'app.settings.basic.country': 'Country/Region',
+  'app.settings.basic.country-message': 'Please input your country!',
+  'app.settings.basic.geographic': 'Province or city',
+  'app.settings.basic.geographic-message': 'Please input your geographic info!',
+  'app.settings.basic.address': 'Street Address',
+  'app.settings.basic.address-message': 'Please input your address!',
+  'app.settings.basic.phone': 'Phone Number',
+  'app.settings.basic.phone-message': 'Please input your phone!',
+  'app.settings.basic.update': 'Update Information',
+  'app.settings.security.strong': 'Strong',
+  'app.settings.security.medium': 'Medium',
+  'app.settings.security.weak': 'Weak',
+  'app.settings.security.password': 'Account Password',
+  'app.settings.security.password-description': 'Current password strength',
+  'app.settings.security.phone': 'Security Phone',
+  'app.settings.security.phone-description': 'Bound phone',
+  'app.settings.security.question': 'Security Question',
+  'app.settings.security.question-description':
+    'The security question is not set, and the security policy can effectively protect the account security',
+  'app.settings.security.email': 'Backup Email',
+  'app.settings.security.email-description': 'Bound Email',
+  'app.settings.security.mfa': 'MFA Device',
+  'app.settings.security.mfa-description':
+    'Unbound MFA device, after binding, can be confirmed twice',
+  'app.settings.security.modify': 'Modify',
+  'app.settings.security.set': 'Set',
+  'app.settings.security.bind': 'Bind',
+  'app.settings.binding.taobao': 'Binding Taobao',
+  'app.settings.binding.taobao-description': 'Currently unbound Taobao account',
+  'app.settings.binding.alipay': 'Binding Alipay',
+  'app.settings.binding.alipay-description': 'Currently unbound Alipay account',
+  'app.settings.binding.dingding': 'Binding DingTalk',
+  'app.settings.binding.dingding-description': 'Currently unbound DingTalk account',
+  'app.settings.binding.bind': 'Bind',
+  'app.settings.notification.password': 'Account Password',
+  'app.settings.notification.password-description':
+    'Messages from other users will be notified in the form of a station letter',
+  'app.settings.notification.messages': 'System Messages',
+  'app.settings.notification.messages-description':
+    'System messages will be notified in the form of a station letter',
+  'app.settings.notification.todo': 'To-do Notification',
+  'app.settings.notification.todo-description':
+    'The to-do list will be notified in the form of a letter from the station',
+  'app.settings.open': 'Open',
+  'app.settings.close': 'Close',
+};

+ 13 - 0
src/locales/zh-CN.ts

@@ -0,0 +1,13 @@
+import component from './zh-CN/component';
+import globalHeader from './zh-CN/globalHeader';
+import menu from './zh-CN/menu';
+import settings from './zh-CN/settings';
+import pages from './zh-CN/pages';
+
+export default {
+  ...pages,
+  ...globalHeader,
+  ...menu,
+  ...settings,
+  ...component,
+};

+ 5 - 0
src/locales/zh-CN/component.ts

@@ -0,0 +1,5 @@
+export default {
+  'component.tagSelect.expand': '展开',
+  'component.tagSelect.collapse': '收起',
+  'component.tagSelect.all': '全部',
+};

+ 17 - 0
src/locales/zh-CN/globalHeader.ts

@@ -0,0 +1,17 @@
+export default {
+  'component.globalHeader.search': '站内搜索',
+  'component.globalHeader.search.example1': '搜索提示一',
+  'component.globalHeader.search.example2': '搜索提示二',
+  'component.globalHeader.search.example3': '搜索提示三',
+  'component.globalHeader.help': '使用文档',
+  'component.globalHeader.notification': '通知',
+  'component.globalHeader.notification.empty': '你已查看所有通知',
+  'component.globalHeader.message': '消息',
+  'component.globalHeader.message.empty': '您已读完所有消息',
+  'component.globalHeader.event': '待办',
+  'component.globalHeader.event.empty': '你已完成所有待办',
+  'component.noticeIcon.clear': '清空',
+  'component.noticeIcon.cleared': '清空了',
+  'component.noticeIcon.empty': '暂无数据',
+  'component.noticeIcon.view-more': '查看更多',
+};

+ 55 - 0
src/locales/zh-CN/menu.ts

@@ -0,0 +1,55 @@
+export default {
+  'menu.environment': '环境信息',
+  'menu.equipment': '设备管理',
+  'menu.runtime': '运行时间',
+  'menu.welcome': '欢迎',
+  'menu.more-blocks': '更多区块',
+  'menu.home': '首页',
+  'menu.admin': '管理页',
+  'menu.admin.sub-page': '二级管理页',
+  'menu.login': '登录',
+  'menu.register': '注册',
+  'menu.register-result': '注册结果',
+  'menu.dashboard': 'Dashboard',
+  'menu.dashboard.analysis': '分析页',
+  'menu.dashboard.monitor': '监控页',
+  'menu.dashboard.workplace': '工作台',
+  'menu.exception.403': '403',
+  'menu.exception.404': '404',
+  'menu.exception.500': '500',
+  'menu.form': '表单页',
+  'menu.form.basic-form': '基础表单',
+  'menu.form.step-form': '分步表单',
+  'menu.form.step-form.info': '分步表单(填写转账信息)',
+  'menu.form.step-form.confirm': '分步表单(确认转账信息)',
+  'menu.form.step-form.result': '分步表单(完成)',
+  'menu.form.advanced-form': '高级表单',
+  'menu.list': '列表页',
+  'menu.list.table-list': '查询表格',
+  'menu.list.basic-list': '标准列表',
+  'menu.list.card-list': '卡片列表',
+  'menu.list.search-list': '搜索列表',
+  'menu.list.search-list.articles': '搜索列表(文章)',
+  'menu.list.search-list.projects': '搜索列表(项目)',
+  'menu.list.search-list.applications': '搜索列表(应用)',
+  'menu.profile': '详情页',
+  'menu.profile.basic': '基础详情页',
+  'menu.profile.advanced': '高级详情页',
+  'menu.result': '结果页',
+  'menu.result.success': '成功页',
+  'menu.result.fail': '失败页',
+  'menu.exception': '异常页',
+  'menu.exception.not-permission': '403',
+  'menu.exception.not-find': '404',
+  'menu.exception.server-error': '500',
+  'menu.exception.trigger': '触发错误',
+  'menu.account': '个人页',
+  'menu.account.center': '个人中心',
+  'menu.account.settings': '个人设置',
+  'menu.account.trigger': '触发报错',
+  'menu.account.logout': '退出登录',
+  'menu.editor': '图形编辑器',
+  'menu.editor.flow': '流程编辑器',
+  'menu.editor.mind': '脑图编辑器',
+  'menu.editor.koni': '拓扑编辑器',
+};

+ 67 - 0
src/locales/zh-CN/pages.ts

@@ -0,0 +1,67 @@
+export default {
+  'pages.layouts.userLayout.title': 'Ant Design 是西湖区最具影响力的 Web 设计规范',
+  'pages.login.accountLogin.tab': '账户密码登录',
+  'pages.login.accountLogin.errorMessage': '错误的用户名和密码(admin/ant.design)',
+  'pages.login.failure': '登录失败,请重试!',
+  'pages.login.success': '登录成功!',
+  'pages.login.username.placeholder': '用户名: admin or user',
+  'pages.login.username.required': '用户名是必填项!',
+  'pages.login.password.placeholder': '密码: ant.design',
+  'pages.login.password.required': '密码是必填项!',
+  'pages.login.phoneLogin.tab': '手机号登录',
+  'pages.login.phoneLogin.errorMessage': '验证码错误',
+  'pages.login.phoneNumber.placeholder': '请输入手机号!',
+  'pages.login.phoneNumber.required': '手机号是必填项!',
+  'pages.login.phoneNumber.invalid': '不合法的手机号!',
+  'pages.login.captcha.placeholder': '请输入验证码!',
+  'pages.login.captcha.required': '验证码是必填项!',
+  'pages.login.phoneLogin.getVerificationCode': '获取验证码',
+  'pages.getCaptchaSecondText': '秒后重新获取',
+  'pages.login.rememberMe': '自动登录',
+  'pages.login.forgotPassword': '忘记密码 ?',
+  'pages.login.submit': '登录',
+  'pages.login.loginWith': '其他登录方式 :',
+  'pages.login.registerAccount': '注册账户',
+  'pages.welcome.advancedComponent': '高级表格',
+  'pages.welcome.link': '欢迎使用',
+  'pages.welcome.advancedLayout': '高级布局',
+  'pages.welcome.alertMessage': '更快更强的重型组件,已经发布。',
+  'pages.admin.subPage.title': ' 这个页面只有 admin 权限才能查看',
+  'pages.admin.subPage.alertMessage': 'umi ui 现已发布,欢迎使用 npm run ui 启动体验。',
+  'pages.searchTable.createForm.newRule': '新建规则',
+  'pages.searchTable.updateForm.ruleConfig': '规则配置',
+  'pages.searchTable.updateForm.basicConfig': '基本信息',
+  'pages.searchTable.updateForm.ruleName.nameLabel': '规则名称',
+  'pages.searchTable.updateForm.ruleName.nameRules': '请输入规则名称!',
+  'pages.searchTable.updateForm.ruleDesc.descLabel': '规则描述',
+  'pages.searchTable.updateForm.ruleDesc.descPlaceholder': '请输入至少五个字符',
+  'pages.searchTable.updateForm.ruleDesc.descRules': '请输入至少五个字符的规则描述!',
+  'pages.searchTable.updateForm.ruleProps.title': '配置规则属性',
+  'pages.searchTable.updateForm.object': '监控对象',
+  'pages.searchTable.updateForm.ruleProps.templateLabel': '规则模板',
+  'pages.searchTable.updateForm.ruleProps.typeLabel': '规则类型',
+  'pages.searchTable.updateForm.schedulingPeriod.title': '设定调度周期',
+  'pages.searchTable.updateForm.schedulingPeriod.timeLabel': '开始时间',
+  'pages.searchTable.updateForm.schedulingPeriod.timeRules': '请选择开始时间!',
+  'pages.searchTable.titleDesc': '描述',
+  'pages.searchTable.ruleName': '规则名称为必填项',
+  'pages.searchTable.titleCallNo': '服务调用次数',
+  'pages.searchTable.titleStatus': '状态',
+  'pages.searchTable.nameStatus.default': '关闭',
+  'pages.searchTable.nameStatus.running': '运行中',
+  'pages.searchTable.nameStatus.online': '已上线',
+  'pages.searchTable.nameStatus.abnormal': '异常',
+  'pages.searchTable.titleUpdatedAt': '上次调度时间',
+  'pages.searchTable.exception': '请输入异常原因!',
+  'pages.searchTable.titleOption': '操作',
+  'pages.searchTable.config': '配置',
+  'pages.searchTable.subscribeAlert': '订阅警报',
+  'pages.searchTable.title': '查询表格',
+  'pages.searchTable.new': '新建',
+  'pages.searchTable.chosen': '已选择',
+  'pages.searchTable.item': '项',
+  'pages.searchTable.totalServiceCalls': '服务调用次数总计',
+  'pages.searchTable.tenThousand': '万',
+  'pages.searchTable.batchDeletion': '批量删除',
+  'pages.searchTable.batchApproval': '批量审批',
+};

+ 55 - 0
src/locales/zh-CN/settings.ts

@@ -0,0 +1,55 @@
+export default {
+  'app.settings.menuMap.basic': '基本设置',
+  'app.settings.menuMap.security': '安全设置',
+  'app.settings.menuMap.binding': '账号绑定',
+  'app.settings.menuMap.notification': '新消息通知',
+  'app.settings.basic.avatar': '头像',
+  'app.settings.basic.change-avatar': '更换头像',
+  'app.settings.basic.email': '邮箱',
+  'app.settings.basic.email-message': '请输入您的邮箱!',
+  'app.settings.basic.nickname': '昵称',
+  'app.settings.basic.nickname-message': '请输入您的昵称!',
+  'app.settings.basic.profile': '个人简介',
+  'app.settings.basic.profile-message': '请输入个人简介!',
+  'app.settings.basic.profile-placeholder': '个人简介',
+  'app.settings.basic.country': '国家/地区',
+  'app.settings.basic.country-message': '请输入您的国家或地区!',
+  'app.settings.basic.geographic': '所在省市',
+  'app.settings.basic.geographic-message': '请输入您的所在省市!',
+  'app.settings.basic.address': '街道地址',
+  'app.settings.basic.address-message': '请输入您的街道地址!',
+  'app.settings.basic.phone': '联系电话',
+  'app.settings.basic.phone-message': '请输入您的联系电话!',
+  'app.settings.basic.update': '更新基本信息',
+  'app.settings.security.strong': '强',
+  'app.settings.security.medium': '中',
+  'app.settings.security.weak': '弱',
+  'app.settings.security.password': '账户密码',
+  'app.settings.security.password-description': '当前密码强度',
+  'app.settings.security.phone': '密保手机',
+  'app.settings.security.phone-description': '已绑定手机',
+  'app.settings.security.question': '密保问题',
+  'app.settings.security.question-description': '未设置密保问题,密保问题可有效保护账户安全',
+  'app.settings.security.email': '备用邮箱',
+  'app.settings.security.email-description': '已绑定邮箱',
+  'app.settings.security.mfa': 'MFA 设备',
+  'app.settings.security.mfa-description': '未绑定 MFA 设备,绑定后,可以进行二次确认',
+  'app.settings.security.modify': '修改',
+  'app.settings.security.set': '设置',
+  'app.settings.security.bind': '绑定',
+  'app.settings.binding.taobao': '绑定淘宝',
+  'app.settings.binding.taobao-description': '当前未绑定淘宝账号',
+  'app.settings.binding.alipay': '绑定支付宝',
+  'app.settings.binding.alipay-description': '当前未绑定支付宝账号',
+  'app.settings.binding.dingding': '绑定钉钉',
+  'app.settings.binding.dingding-description': '当前未绑定钉钉账号',
+  'app.settings.binding.bind': '绑定',
+  'app.settings.notification.password': '账户密码',
+  'app.settings.notification.password-description': '其他用户的消息将以站内信的形式通知',
+  'app.settings.notification.messages': '系统消息',
+  'app.settings.notification.messages-description': '系统消息将以站内信的形式通知',
+  'app.settings.notification.todo': '待办任务',
+  'app.settings.notification.todo-description': '待办任务将以站内信的形式通知',
+  'app.settings.open': '开',
+  'app.settings.close': '关',
+};

+ 22 - 0
src/manifest.json

@@ -0,0 +1,22 @@
+{
+  "name": "Ant Design Pro",
+  "short_name": "Ant Design Pro",
+  "display": "standalone",
+  "start_url": "./?utm_source=homescreen",
+  "theme_color": "#002140",
+  "background_color": "#001529",
+  "icons": [
+    {
+      "src": "icons/icon-192x192.png",
+      "sizes": "192x192"
+    },
+    {
+      "src": "icons/icon-128x128.png",
+      "sizes": "128x128"
+    },
+    {
+      "src": "icons/icon-512x512.png",
+      "sizes": "512x512"
+    }
+  ]
+}

+ 0 - 0
src/models/global.js


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません