Browse Source

change

pull/10914/head
期贤 3 years ago
parent
commit
e1b5ad5a97
  1. 35
      .dockerignore
  2. 3
      .eslintrc.js
  3. 16
      .github/ISSUE_TEMPLATE/bug_report.md
  4. 15
      .github/ISSUE_TEMPLATE/feature_request.md
  5. 23
      .github/ISSUE_TEMPLATE/question.md
  6. 4
      .github/workflows/ci.yml
  7. 41
      .github/workflows/codeql.yml
  8. 27
      .github/workflows/coverage.yml
  9. 31
      .github/workflows/deploy.yml
  10. 8
      .github/workflows/issue-open-check.yml
  11. 33
      .github/workflows/pnpm.yml
  12. 3
      .github/workflows/preview-build.yml
  13. 11
      .github/workflows/preview-deploy.yml
  14. 6
      .github/workflows/preview-start.yml
  15. 17
      .github/workflows/rebase.yml
  16. 3
      .gitignore
  17. 6
      .gitpod.yml
  18. 1
      .husky/.gitignore
  19. 1
      .prettierignore
  20. 22
      .prettierrc.js
  21. 3
      .stylelintrc.js
  22. 8
      .vscode/extensions.json
  23. 5
      .vscode/settings.json
  24. 14
      Dockerfile
  25. 12
      Dockerfile.dev
  26. 27
      Dockerfile.hub
  27. 2
      LICENSE
  28. 14
      README.ar-DZ.md
  29. 14
      README.fr-FR.md
  30. 14
      README.ja-JP.md
  31. 52
      README.md
  32. 14
      README.pt-BR.md
  33. 6
      README.ru-RU.md
  34. 22
      README.tr-TR.md
  35. 53
      README.zh-CN.md
  36. 15
      config/config.dev.ts
  37. 444
      config/config.ts
  38. 15
      config/defaultSettings.ts
  39. 32
      config/proxy.ts
  40. 32
      config/routes.ts
  41. 14
      docker/docker-compose.dev.yml
  42. 21
      docker/docker-compose.yml
  43. 21
      docker/nginx.conf
  44. 9
      jest.config.js
  45. 23
      jest.config.ts
  46. 10
      mock/listTableList.ts
  47. 24
      mock/notices.ts
  48. 324
      mock/requestRecord.mock.js
  49. 138
      package.json
  50. 22
      playwright.config.ts
  51. 18934
      pnpm-lock.yaml
  52. 128
      public/scripts/loading.js
  53. 104
      src/app.tsx
  54. 8
      src/components/Footer/index.tsx
  55. 16
      src/components/HeaderDropdown/index.less
  56. 18
      src/components/HeaderDropdown/index.tsx
  57. 25
      src/components/HeaderSearch/index.less
  58. 102
      src/components/HeaderSearch/index.tsx
  59. 126
      src/components/NoticeIcon/NoticeIcon.tsx
  60. 103
      src/components/NoticeIcon/NoticeList.less
  61. 113
      src/components/NoticeIcon/NoticeList.tsx
  62. 35
      src/components/NoticeIcon/index.less
  63. 153
      src/components/NoticeIcon/index.tsx
  64. 136
      src/components/RightContent/AvatarDropdown.tsx
  65. 84
      src/components/RightContent/index.less
  66. 81
      src/components/RightContent/index.tsx
  67. 272
      src/components/index.md
  68. 45
      src/e2e/baseLayout.e2e.spec.ts
  69. 17
      src/global.less
  70. 42
      src/global.style.ts
  71. 4
      src/global.tsx
  72. 2
      src/locales/bn-BD/pages.ts
  73. 4
      src/locales/en-US/pages.ts
  74. 2
      src/locales/fa-IR.ts
  75. 4
      src/locales/fa-IR/pages.ts
  76. 2
      src/locales/id-ID.ts
  77. 4
      src/locales/id-ID/pages.ts
  78. 6
      src/locales/ja-JP.ts
  79. 4
      src/locales/ja-JP/pages.ts
  80. 2
      src/locales/pt-BR.ts
  81. 1
      src/locales/pt-BR/globalHeader.ts
  82. 2
      src/locales/pt-BR/menu.ts
  83. 4
      src/locales/pt-BR/pages.ts
  84. 2
      src/locales/zh-CN.ts
  85. 2
      src/locales/zh-CN/pages.ts
  86. 18
      src/locales/zh-TW/menu.ts
  87. 65
      src/locales/zh-TW/pages.ts
  88. 2
      src/pages/404.tsx
  89. 12
      src/pages/Admin.tsx
  90. 16
      src/pages/TableList/components/UpdateForm.tsx
  91. 46
      src/pages/TableList/index.tsx
  92. 1114
      src/pages/User/Login/__snapshots__/login.test.tsx.snap
  93. 193
      src/pages/User/Login/index.tsx
  94. 96
      src/pages/User/Login/login.test.tsx
  95. 27
      src/pages/User/register-result/style.style.ts
  96. 41
      src/pages/User/register/style.style.ts
  97. 8
      src/pages/Welcome.less
  98. 196
      src/pages/Welcome.tsx
  99. 2
      src/pages/account/center/Center.less
  100. 76
      src/pages/account/center/Center.style.ts

35
.dockerignore

@ -1,35 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
**/node_modules
/src/utils/request-temp.js
# production
/.vscode
# misc
.DS_Store
npm-debug.log*
yarn-error.log
/coverage
.idea
yarn.lock
package-lock.json
*bak
.vscode
# visual studio code
.history
*.log
functions/mock
.temp/**
# umi
.umi
.umi-production
# screenshot
screenshot
.firebase

3
.eslintrc.js

@ -1,7 +1,6 @@
module.exports = {
extends: [require.resolve('@umijs/fabric/dist/eslint')],
extends: [require.resolve('@umijs/lint/dist/config/eslint')],
globals: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
page: true,
REACT_APP_ENV: true,
},

16
.github/ISSUE_TEMPLATE/bug_report.md

@ -1,8 +1,8 @@
---
name: '报告Bug 🐛'
name: '报告 Bug | Report bug 🐛'
about: 报告 Ant Design Pro 的 bug
title: '🐛[BUG]'
labels: '🐛bug'
title: '🐛 [BUG]'
labels: '🐛 bug'
assignees: ''
---
@ -10,24 +10,28 @@ assignees: ''
<!--
详细地描述 bug,让大家都能理解
Describe the bug in detail so that everyone can understand it
-->
### 📷 复现步骤
### 📷 复现步骤 | Recurrence steps
<!--
清晰描述复现步骤,让别人也能看到问题
Clearly describe the recurrence steps so that others can see the problem
-->
### 🏞 期望结果
### 🏞 期望结果 | Expected results
<!--
描述你原本期望看到的结果
Describe what you expected to see
-->
### 💻 复现代码
### 💻 复现代码 | Recurrence code
<!--
提供可复现的代码,仓库,或线上示例
Provide reproducible code, warehouse, or online examples
-->
### © 版本信息

15
.github/ISSUE_TEMPLATE/feature_request.md

@ -1,25 +1,28 @@
---
name: '功能需求 ✨'
name: '功能需求 | Feature Requirements ✨'
about: 对 Ant Design Pro 的需求或建议
title: '👑 [需求]'
labels: '👑Feature Request'
title: '👑 [需求 | Feature]'
labels: '👑 Feature Request'
assignees: ''
---
### 🥰 需求描述
### 🥰 需求描述 | Requirements description
<!--
详细地描述需求,让大家都能理解
Describe the requirements in detail so that everyone can understand them
-->
### 🧐 解决方案
### 🧐 解决方案 | Solution
<!--
如果你有解决方案,在这里清晰地阐述
If you have a solution, explain it clearly here
-->
### 🚑 其他信息
### 🚑 其他信息 | Other information
<!--
如截图等其他信息可以贴在这里
Other information such as screenshots can be posted here
-->

23
.github/ISSUE_TEMPLATE/question.md

@ -1,25 +1,34 @@
---
name: '疑问或需要帮助 ❓'
name: '疑问或需要帮助 | Questions or need help ❓'
about: 对 Ant Design Pro 使用的疑问或需要帮助
title: '🧐[问题]'
labels: '🧐question'
title: '🧐[问题 | question]'
labels: '🧐 question'
assignees: ''
---
### 🧐 问题描述
### 🧐 问题描述 | Problem description
<!--
详细地描述问题,让大家都能理解
Describe the problem in detail so that everyone can understand it
-->
### 💻 示例代码
### 💻 示例代码 | Sample code
<!--
如果你有解决方案,在这里清晰地阐述
一个最小可重现的代码,让开发者可以快速的定位问题
A minimal reproducible code that allows developers to quickly locate problems
-->
### 🚑 其他信息
### 🚑 其他信息 | Other information
<!--
如截图等其他信息可以贴在这里
Other information such as screenshots can be posted here
-->
OS:
Node:
浏览器 | browser:

4
.github/workflows/ci.yml

@ -2,6 +2,9 @@ name: Node CI
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ${{ matrix.os }}
@ -20,7 +23,6 @@ jobs:
- run: yarn run lint
- run: yarn run tsc
- run: yarn run build
- run: yarn run test:e2e
env:
CI: true
PROGRESS: none

41
.github/workflows/codeql.yml

@ -0,0 +1,41 @@
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
schedule:
- cron: "48 12 * * 2"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ javascript ]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"

27
.github/workflows/coverage.yml

@ -0,0 +1,27 @@
name: coverage CI
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 16.x
- run: echo ${{github.ref}}
- run: curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7
- run: pnpm config set store-dir ~/.pnpm-store
- run: pnpm install --strict-peer-dependencies=false
- run: yarn run test:coverage
env:
CI: true
PROGRESS: none
NODE_ENV: test
NODE_OPTIONS: --max_old_space_size=4096
- run: bash <(curl -s https://codecov.io/bash)

31
.github/workflows/deploy.yml

@ -1,31 +0,0 @@
name: Deploy CI
on:
push:
branches:
- master
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@master
- name: install
run: yarn
- name: plugins
run: yarn add umi-plugin-pro
- name: fetch-blocks
run: yarn run pro fetch-blocks
- name: site
run: npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
force_orphan: true

8
.github/workflows/issue-open-check.yml

@ -13,7 +13,7 @@ jobs:
with:
actions: 'check-issue'
issue-number: ${{ github.event.issue.number }}
title-excludes: '🐛[BUG], 👑 [需求], 🧐[问题]'
title-excludes: '🐛 [BUG], 👑 [需求 | Feature], 🧐[问题 | question]'
- if: steps.check.outputs.check-result == 'false' && github.event.issue.state == 'open'
uses: actions-cool/issues-helper@v2.2.0
@ -26,9 +26,9 @@ jobs:
The title of the current issue is not detected, please fill in according to the specifications, thank you!
- if: steps.check.outputs.check-result == 'true'
uses: actions-cool/issues-similarity-analysis@v1.1.0
uses: actions-cool/issues-similarity-analysis@v1
with:
filter-threshold: 0.6
title-excludes: '🐛[BUG], 👑 [需求], 🧐[问题]'
filter-threshold: 0.8
title-excludes: '🐛[BUG], 👑 [需求 | Feature], 🧐[问题 | question]'
comment-title: '### 以下的 Issues 可能会帮助到你 / The following issues may help you'
show-footer: false

33
.github/workflows/pnpm.yml

@ -0,0 +1,33 @@
name: Node pnpm CI
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
node_version: [16.x]
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node_version }}
- run: echo ${{github.ref}}
- run: curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm@7
- run: pnpm config set store-dir ~/.pnpm-store
- run: pnpm install --strict-peer-dependencies=false
- run: pnpm run lint
- run: pnpm run tsc
- run: pnpm run build
- run: pnpm run test
env:
CI: true
PROGRESS: none
NODE_ENV: test
NODE_OPTIONS: --max_old_space_size=4096

3
.github/workflows/preview-build.yml

@ -4,6 +4,9 @@ on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
jobs:
build-preview:
runs-on: ubuntu-latest

11
.github/workflows/preview-deploy.yml

@ -6,8 +6,15 @@ on:
types:
- completed
permissions:
contents: read
jobs:
success:
permissions:
actions: read # for dawidd6/action-download-artifact to query and download artifacts
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
runs-on: ubuntu-latest
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
steps:
@ -62,6 +69,10 @@ jobs:
number: ${{ steps.pr.outputs.id }}
failed:
permissions:
actions: read # for dawidd6/action-download-artifact to query and download artifacts
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
runs-on: ubuntu-latest
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'failure'
steps:

6
.github/workflows/preview-start.yml

@ -2,8 +2,14 @@ name: Preview Start
on: pull_request_target
permissions:
contents: read
jobs:
preview:
permissions:
issues: write # for actions-cool/maintain-one-comment to modify or create issue comments
pull-requests: write # for actions-cool/maintain-one-comment to modify or create PR comments
runs-on: ubuntu-latest
steps:
- name: create

17
.github/workflows/rebase.yml

@ -1,17 +0,0 @@
on:
issue_comment:
types: [created]
name: Automatic Rebase
jobs:
rebase:
name: Rebase
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
with:
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

3
.gitignore

@ -18,8 +18,8 @@ yarn-error.log
.idea
yarn.lock
package-lock.json
pnpm-lock.yaml
*bak
.vscode
# visual studio code
@ -31,6 +31,7 @@ functions/*
# umi
.umi
.umi-production
.umi-test
# screenshot
screenshot

6
.gitpod.yml

@ -1,6 +0,0 @@
ports:
- port: 8000
onOpen: open-preview
tasks:
- init: npm install
command: npm start

1
.husky/.gitignore

@ -1 +0,0 @@
_

1
.prettierignore

@ -1,5 +1,4 @@
**/*.svg
package.json
.umi
.umi-production
/dist

22
.prettierrc.js

@ -1,5 +1,21 @@
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.prettier,
singleQuote: true,
trailingComma: 'all',
printWidth: 100,
proseWrap: 'never',
endOfLine: 'lf',
overrides: [
{
files: '.prettierrc',
options: {
parser: 'json',
},
},
{
files: 'document.ejs',
options: {
parser: 'html',
},
},
],
};

3
.stylelintrc.js

@ -1,3 +0,0 @@
module.exports = {
extends: [require.resolve('@umijs/fabric/dist/stylelint')],
};

8
.vscode/extensions.json

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

5
.vscode/settings.json

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

14
Dockerfile

@ -1,14 +0,0 @@
FROM circleci/node:latest-browsers
WORKDIR /usr/src/app/
USER root
COPY package.json ./
RUN yarn
COPY ./ ./
RUN npm run test:e2e
RUN npm run fetch:blocks
CMD ["npm", "run", "build"]

12
Dockerfile.dev

@ -1,12 +0,0 @@
FROM node:latest
WORKDIR /usr/src/app/
COPY package.json ./
RUN npm install --silent --no-cache --registry=https://registry.npmmirror.com
COPY ./ ./
RUN npm run fetch:blocks
CMD ["npm", "run", "start"]

27
Dockerfile.hub

@ -1,27 +0,0 @@
FROM circleci/node:latest-browsers as builder
WORKDIR /usr/src/app/
USER root
COPY package.json ./
RUN yarn
COPY ./ ./
RUN npm run test:e2e
RUN npm run fetch:blocks
RUN npm run build
FROM nginx
WORKDIR /usr/share/nginx/html/
COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /usr/src/app/dist /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

2
LICENSE

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 Alipay.inc
Copyright (c) 2019-present Alipay.inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

14
README.ar-DZ.md

@ -109,21 +109,13 @@ $ npm start # visit http://localhost:8000
<div dir="rtl">
### استخدام ال Gitpod
افتح المشروع في Gitpod (بيئة تطوير مجانية عبر الإنترنت لـ GitHub) وابدأ بكتابة الكود على الفور.
[![افتح في Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
المزيد من التعليمات في [توثيق](http://pro.ant.design/docs/getting-started).
## دعم المتصفحات
المتصفحات الحديثة و IE11.
المتصفحات الحديثة و.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --- | --- | --- | --- | --- |
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## المساهمة

14
README.fr-FR.md

@ -96,21 +96,13 @@ $ npm install
$ npm start # visit http://localhost:8000
```
### Utilisation de Gitpod
Ouvrez le projet avec Gitpod (environnement de développement gratuit pour GitHub) et commencez à coder immédiatement.
[![Ouvrir dans Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
Plus d'instructions dans la [documentation](http://pro.ant.design/docs/getting-started).
## Support des navigateurs
Navigateurs modernes et IE11.
Navigateurs modernes.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --- | --- | --- | --- | --- |
| IE11, Edge | deux dernières versions | deux dernières versions | deux dernières versions | deux dernières versions |
| Edge | deux dernières versions | deux dernières versions | deux dernières versions | deux dernières versions |
## Contribution

14
README.ja-JP.md

@ -96,21 +96,13 @@ $ npm install
$ npm start # http://localhost:8000 を開く
```
### Gitpod を使う方法
Gitpod(GitHub 用の無料オンライン開発環境)でプロジェクトを開き、すぐにコーディングを開始できます。
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
その他の指示は [ドキュメント](http://pro.ant.design/docs/getting-started) を確認してください。
## サポートするブラウザー
モダンなブラウザと IE11
モダンなブラウザと。
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --- | --- | --- | --- | --- |
| IE11, Edge | 最新版から 2 バージョン | 最新版から 2 バージョン | 最新版から 2 バージョン | 最新版から 2 バージョン |
| Edge | 最新版から 2 バージョン | 最新版から 2 バージョン | 最新版から 2 バージョン | 最新版から 2 バージョン |
## 貢献する

52
README.md

@ -82,39 +82,47 @@ We need your help: https://github.com/ant-design/ant-design-pro/issues/120
### Use bash
We provide pro-cli to quickly initialize scaffolding.
```bash
$ mkdir <your-project-name>
$ cd <your-project-name>
$ yarn create umi # or npm create umi
# Choose ant-design-pro:
Select the boilerplate type (Use arrow keys)
❯ ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block.
app - Create project with a simple boilerplate, support typescript.
block - Create a umi block.
library - Create a library with umi.
plugin - Create a umi plugin.
$ git init
$ npm install
$ npm start # visit http://localhost:8000
# use npm
npm i @ant-design/pro-cli -g
pro create myapp
```
### Use Gitpod
select umi version
```shell
🐂 Use umi@4 or umi@3 ? (Use arrow keys)
❯ umi@4
umi@3
```
Open the project in Gitpod (free online dev environment for GitHub) and start coding immediately.
> If the umi@4 version is selected, full blocks are not yet supported.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
If you choose umi@3, you can also choose the pro template. Pro is the basic template, which only provides the basic content of the framework operation. Complete contains all blocks, which is not suitable for secondary development as a basic template.
More instructions at [documentation](http://pro.ant.design/docs/getting-started).
```shell
? 🚀 Full or a simple scaffold? (Use arrow keys)
❯ simple
complete
```
Install dependencies:
```shell
$ cd myapp && tyarn
// or
$ cd myapp && npm install
```
## Browsers support
Modern browsers and IE11.
Modern browsers.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --- | --- | --- | --- | --- |
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## Contributing

14
README.pt-BR.md

@ -98,21 +98,13 @@ $ npm install
$ npm start # visit http://localhost:8000
```
### Use Gitpod
Abra o projeto no Gitpod (ambiente gratuito de desenvolvimento online para o GitHub) e comece a codificar imediatamente.
[![Abra no Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
Mais instruções na [documentação](http://pro.ant.design/docs/getting-started).
## Suporte a navegadores
Navegadores modernos e IE11.
Navegadores modernos .
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --- | --- | --- | --- | --- |
| IE11, Edge | últimas 2 versões | últimas 2 versões | últimas 2 versões | últimas 2 versões |
| Edge | últimas 2 versões | últimas 2 versões | últimas 2 versões | últimas 2 versões |
## Contribuindo

6
README.ru-RU.md

@ -94,11 +94,11 @@ $ npm start # visit http://localhost:8000
## Совместимость
Современные браузеры и IE11.
Современные браузеры.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --- | --- | --- | --- | --- |
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## Распространение

22
README.tr-TR.md

@ -6,7 +6,9 @@ Language : [🇺🇸](./README.md) | [🇨🇳](./README.zh-CN.md) | [🇷🇺](
React ile kurumsal uygulamalar için taslak olarak geliştirilmiş kullanıma hazır bir UI çözümü.
[![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) [![Build Status](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=master) [![Dependencies](https://img.shields.io/david/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro) [![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro?type=dev) [![Gitter](https://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Join the chat at https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label) ![Github Action](https://github.com/ant-design/ant-design-pro/workflows/Node%20CI/badge.svg)
[![Build Status](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=master) ![Github Action](https://github.com/ant-design/ant-design-pro/workflows/Node%20CI/badge.svg) ![Deploy](https://github.com/ant-design/ant-design-pro/workflows/Deploy%20CI/badge.svg)
[![Gitter](https://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Join the chat at https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)
![](https://user-images.githubusercontent.com/8186664/44953195-581e3d80-aec4-11e8-8dcb-54b9db38ec11.png)
@ -19,9 +21,9 @@ React ile kurumsal uygulamalar için taslak olarak geliştirilmiş kullanıma ha
- SSS: http://pro.ant.design/docs/faq
- Çinde barındırılan site: http://ant-design-pro.gitee.io
## 4.0 Versiyonu Şimdi Yayında! 🎉🎉🎉
## 5.0 Versiyonu Şimdi Yayında! 🎉🎉🎉
[Announcing Ant Design Pro 4.0.0](https://medium.com/ant-design/ant-design-pro-v4-is-here-6f23098ae9d9)
[Ant Design Pro 5.0.0](https://github.com/ant-design/ant-design-pro/issues/8656)
## Çeviri Desteği :loudspeaker:
@ -98,21 +100,13 @@ $ npm install
$ npm start # visit http://localhost:8000
```
### Gitpod ile
Projeyi Gitpod'da (GitHub için ücretsiz geliştirme ortamı) açın ve anında kodlamaya başlayın.
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/ant-design/ant-design-pro)
Daha fazla talimat için [dokümantasyon](http://pro.ant.design/docs/getting-started) sayfasına göz atın.
## Tarayıcı desteği
Modern internet tarayıcıları ve IE11.
Modern internet tarayıcıları .
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --- | --- | --- | --- | --- |
| IE11, Edge | son 2 versiyon | son 2 versiyon | son 2 versiyon | son 2 versiyon |
| Edge | son 2 versiyon | son 2 versiyon | son 2 versiyon | son 2 versiyon |
## Destek

53
README.zh-CN.md

@ -22,6 +22,7 @@ Language : [🇺🇸](./README.md) | 🇨🇳 | [🇷🇺](./README.ru-RU.md) |
## 5.0 已经发布! 🎉🎉🎉
[Ant Design Pro 5.0.0](https://github.com/ant-design/ant-design-pro/issues/8656)
## 特性
- :bulb: **TypeScript**: 应用程序级 JavaScript 的语言
@ -73,33 +74,49 @@ Language : [🇺🇸](./README.md) | 🇨🇳 | [🇷🇺](./README.ru-RU.md) |
## 使用
我们提供了 pro-cli 来快速的初始化脚手架。
```bash
$ mkdir <your-project-name>
$ cd <your-project-name>
$ yarn create umi # or npm create umi
# Choose ant-design-pro:
Select the boilerplate type (Use arrow keys)
❯ ant-design-pro - Create project with an layout-only ant-design-pro boilerplate, use together with umi block.
app - Create project with a simple boilerplate, support typescript.
block - Create a umi block.
library - Create a library with umi.
plugin - Create a umi plugin.
$ git init
$ npm install
$ npm start # visit http://localhost:8000
# 使用 npm
npm i @ant-design/pro-cli -g
pro create myapp
```
选择 umi 的版本
```shell
? 🐂 使用 umi@4 还是 umi@3 ? (Use arrow keys)
❯ umi@4
umi@3
```
> 如果选择了 umi@4 版本,暂时还不支持全量区块。
如果选择了 umi@3,还可以选择 pro 的模板,simple 是基础模板,只提供了框架运行的基本内容,complete 包含所有区块,不太适合当基础模板来进行二次开发
```shell
? 🚀 要全量的还是一个简单的脚手架? (Use arrow keys)
❯ simple
complete
```
安装依赖:
```shell
$ cd myapp && tyarn
// 或
$ cd myapp && npm install
```
更多信息请参考 [使用文档](http://pro.ant.design/docs/getting-started)。
## 支持环境
现代浏览器及 IE11。
现代浏览器。
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera |
| --- | --- | --- | --- | --- |
| IE11, Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
| Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 参与贡献

15
config/config.dev.ts

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

444
config/config.ts

@ -1,24 +1,100 @@
// https://umijs.org/config/
import { defineConfig } from 'umi';
import { defineConfig } from '@umijs/max';
import { join } from 'path';
import defaultSettings from './defaultSettings';
import proxy from './proxy';
const { REACT_APP_ENV } = process.env;
import routes from './routes';
const { REACT_APP_ENV = 'dev' } = process.env;
export default defineConfig({
/**
* @name hash
* @description build hash
* @doc https://umijs.org/docs/api/config#hash
*/
hash: true,
antd: {},
dva: {
hmr: true,
/**
* @name
* @description ie11 使
* @doc https://umijs.org/docs/api/config#targets
*/
// targets: {
// ie: 11,
// },
/**
* @name
* @description pathcomponentroutesredirectwrapperstitle
* @doc https://umijs.org/docs/guides/routes
*/
// umi routes: https://umijs.org/docs/routing
routes,
/**
* @name
* @description less
* @doc antd的主题设置 https://ant.design/docs/react/customize-theme-cn
* @doc umi theme https://umijs.org/docs/api/config#theme
*/
theme: {
// 如果不想要 configProvide 动态设置主题需要把这个设置为 default
// 只有设置为 variable, 才能使用 configProvide 动态设置主色调
'root-entry-name': 'variable',
},
/**
* @name moment
* @description js的包大小
* @doc https://umijs.org/docs/api/config#ignoremomentlocale
*/
ignoreMomentLocale: true,
/**
* @name
* @description 访
* @see 使build 使
* @doc https://umijs.org/docs/guides/proxy
* @doc https://umijs.org/docs/api/config#proxy
*/
proxy: proxy[REACT_APP_ENV as keyof typeof proxy],
/**
* @name
* @description state
*/
fastRefresh: true,
//============== 以下都是max的插件配置 ===============
/**
* @name
* @@doc https://umijs.org/docs/max/data-flow
*/
model: {},
/**
*
* @description Umi
* @doc https://umijs.org/docs/max/data-flow#%E5%85%A8%E5%B1%80%E5%88%9D%E5%A7%8B%E7%8A%B6%E6%80%81
*/
initialState: {},
/**
* @name layout
* @doc https://umijs.org/docs/max/layout-menu
*/
title: 'Ant Design Pro',
layout: {
// https://umijs.org/zh-CN/plugins/plugin-layout
locale: true,
siderWidth: 208,
...defaultSettings,
},
// https://umijs.org/zh-CN/plugins/plugin-locale
/**
* @name moment2dayjs
* @description moment dayjs
* @doc https://umijs.org/docs/max/moment2dayjs
*/
moment2dayjs: {
preset: 'antd',
plugins: ['duration'],
},
/**
* @name
* @doc https://umijs.org/docs/max/i18n
*/
locale: {
// default zh-CN
default: 'zh-CN',
@ -26,333 +102,55 @@ export default defineConfig({
// 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: [
{
path: '/user',
layout: false,
routes: [
{
path: '/user/login',
layout: false,
name: 'login',
component: './user/Login',
},
{
path: '/user',
redirect: '/user/login',
},
{
name: 'register-result',
icon: 'smile',
path: '/user/register-result',
component: './user/register-result',
},
{
name: 'register',
icon: 'smile',
path: '/user/register',
component: './user/register',
},
{
component: '404',
},
],
},
{
path: '/dashboard',
name: 'dashboard',
icon: 'dashboard',
routes: [
{
path: '/dashboard',
redirect: '/dashboard/analysis',
},
{
name: 'analysis',
icon: 'smile',
path: '/dashboard/analysis',
component: './dashboard/analysis',
},
{
name: 'monitor',
icon: 'smile',
path: '/dashboard/monitor',
component: './dashboard/monitor',
},
{
name: 'workplace',
icon: 'smile',
path: '/dashboard/workplace',
component: './dashboard/workplace',
},
],
},
{
path: '/form',
icon: 'form',
name: 'form',
routes: [
{
path: '/form',
redirect: '/form/basic-form',
},
{
name: 'basic-form',
icon: 'smile',
path: '/form/basic-form',
component: './form/basic-form',
},
{
name: 'step-form',
icon: 'smile',
path: '/form/step-form',
component: './form/step-form',
},
{
name: 'advanced-form',
icon: 'smile',
path: '/form/advanced-form',
component: './form/advanced-form',
},
],
},
{
path: '/list',
icon: 'table',
name: 'list',
routes: [
{
path: '/list/search',
name: 'search-list',
component: './list/search',
routes: [
{
path: '/list/search',
redirect: '/list/search/articles',
},
{
name: 'articles',
icon: 'smile',
path: '/list/search/articles',
component: './list/search/articles',
},
{
name: 'projects',
icon: 'smile',
path: '/list/search/projects',
component: './list/search/projects',
},
{
name: 'applications',
icon: 'smile',
path: '/list/search/applications',
component: './list/search/applications',
},
],
},
{
path: '/list',
redirect: '/list/table-list',
},
{
name: 'table-list',
icon: 'smile',
path: '/list/table-list',
component: './list/table-list',
},
{
name: 'basic-list',
icon: 'smile',
path: '/list/basic-list',
component: './list/basic-list',
},
{
name: 'card-list',
icon: 'smile',
path: '/list/card-list',
component: './list/card-list',
},
],
},
{
path: '/profile',
name: 'profile',
icon: 'profile',
routes: [
{
path: '/profile',
redirect: '/profile/basic',
},
{
name: 'basic',
icon: 'smile',
path: '/profile/basic',
component: './profile/basic',
},
{
name: 'advanced',
icon: 'smile',
path: '/profile/advanced',
component: './profile/advanced',
},
],
},
{
name: 'result',
icon: 'CheckCircleOutlined',
path: '/result',
routes: [
{
path: '/result',
redirect: '/result/success',
},
{
name: 'success',
icon: 'smile',
path: '/result/success',
component: './result/success',
},
{
name: 'fail',
icon: 'smile',
path: '/result/fail',
component: './result/fail',
},
],
},
{
name: 'exception',
icon: 'warning',
path: '/exception',
routes: [
{
path: '/exception',
redirect: '/exception/403',
},
{
name: '403',
icon: 'smile',
path: '/exception/403',
component: './exception/403',
},
{
name: '404',
icon: 'smile',
path: '/exception/404',
component: './exception/404',
},
{
name: '500',
icon: 'smile',
path: '/exception/500',
component: './exception/500',
},
],
},
{
name: 'account',
icon: 'user',
path: '/account',
routes: [
{
path: '/account',
redirect: '/account/center',
},
{
name: 'center',
icon: 'smile',
path: '/account/center',
component: './account/center',
},
{
name: 'settings',
icon: 'smile',
path: '/account/settings',
component: './account/settings',
},
],
},
{
name: 'editor',
icon: 'highlight',
path: '/editor',
routes: [
{
path: '/editor',
redirect: '/editor/flow',
},
{
name: 'flow',
icon: 'smile',
path: '/editor/flow',
component: './editor/flow',
},
{
name: 'mind',
icon: 'smile',
path: '/editor/mind',
component: './editor/mind',
},
{
name: 'koni',
icon: 'smile',
path: '/editor/koni',
component: './editor/koni',
},
],
},
{
path: '/',
redirect: '/dashboard/analysis',
},
{
component: '404',
},
],
/**
* @name antd
* @description babel import
* @doc https://umijs.org/docs/max/antd#antd
*/
antd: {},
/**
* @name
* @description axios ahooks useRequest
* @doc https://umijs.org/docs/max/request
*/
request: {},
/**
* @name
* @description initialState initialState
* @doc https://umijs.org/docs/max/access
*/
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: {},
/**
* @name <head> script
* @description <head> script
*/
headScripts: [
// 解决首次加载时白屏的问题
{ src: '/scripts/loading.js', async: true },
],
//================ pro 插件配置 =================
presets: ['umi-presets-pro'],
/**
* @name openAPI
* @description openapi serve mock
* @doc https://pro.ant.design/zh-cn/docs/openapi/
*/
openAPI: [
{
requestLibPath: "import { request } from 'umi'",
requestLibPath: "import { request } from '@umijs/max'",
// 或者使用在线的版本
// schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json"
schemaPath: join(__dirname, 'oneapi.json'),
mock: false,
},
{
requestLibPath: "import { request } from 'umi'",
requestLibPath: "import { request } from '@umijs/max'",
schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json',
projectName: 'swagger',
},
],
nodeModulesTransform: {
type: 'none',
mfsu: {
strategy: 'normal',
},
mfsu: {},
webpack5: {},
exportStatic: {},
requestRecord: {},
});

15
config/defaultSettings.ts

@ -1,21 +1,28 @@
import { Settings as LayoutSettings } from '@ant-design/pro-layout';
import { ProLayoutProps } from '@ant-design/pro-components';
const Settings: LayoutSettings & {
/**
* @name
*/
const Settings: ProLayoutProps & {
pwa?: boolean;
logo?: string;
} = {
navTheme: 'light',
// 拂晓蓝
primaryColor: '#1890ff',
colorPrimary: '#1890ff',
layout: 'mix',
contentWidth: 'Fluid',
fixedHeader: false,
fixSiderbar: true,
colorWeak: false,
title: 'Ant Design Pro',
pwa: false,
pwa: true,
logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
iconfontUrl: '',
token: {
// 参见ts声明,demo 见文档,通过token 修改样式
//https://procomponents.ant.design/components/layout#%E9%80%9A%E8%BF%87-token-%E4%BF%AE%E6%94%B9%E6%A0%B7%E5%BC%8F
},
};
export default Settings;

32
config/proxy.ts

@ -1,23 +1,33 @@
/**
*
* @name
* @see
* -------------------------------
* 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
*
* @doc https://umijs.org/docs/guides/proxy
*/
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,
},
},
// 如果需要自定义本地开发服务器 请取消注释按需调整
// dev: {
// // localhost:8000/api/** -> https://preview.pro.ant.design/api/**
// '/api/': {
// // 要代理的地址
// target: 'https://preview.pro.ant.design',
// // 配置了这个可以从 http 代理到 https
// // 依赖 origin 的功能可能需要这个,比如 cookie
// changeOrigin: true,
// },
// },
/**
* @name
* @doc https://github.com/chimurai/http-proxy-middleware
*/
test: {
// localhost:8000/api/** -> https://preview.pro.ant.design/api/**
'/api/': {
target: 'https://proapi.azurewebsites.net',
changeOrigin: true,

32
config/routes.ts

@ -1,4 +1,16 @@
export default [
/**
* @name umi
* @description path,component,routes,redirect,wrappers,name,icon
* @param path path 第一种是动态参数 :id *
* @param component location path React src/pages
* @param routes layout 使
* @param redirect
* @param wrappers
* @param name menu.ts menu.xxxx name login menu.ts menu.login
* @param icon https://ant.design/components/icon-cn, 注意去除风格后缀和大小写,如想要配置图标为 <StepBackwardOutlined /> 则取值应为 stepBackward 或 StepBackward,如想要配置图标为 <UserOutlined /> 则取值应为 user 或者 User
* @doc https://umijs.org/docs/guides/routes
*/
export default [
{
path: '/user',
layout: false,
@ -6,10 +18,7 @@
{
name: 'login',
path: '/user/login',
component: './user/Login',
},
{
component: './404',
component: './User/Login',
},
],
},
@ -24,16 +33,15 @@
name: 'admin',
icon: 'crown',
access: 'canAdmin',
component: './Admin',
routes: [
{
path: '/admin/sub-page',
name: 'sub-page',
icon: 'smile',
component: './Welcome',
path: '/admin',
redirect: '/admin/sub-page',
},
{
component: './404',
path: '/admin/sub-page',
name: 'sub-page',
component: './Admin',
},
],
},
@ -48,6 +56,8 @@
redirect: '/welcome',
},
{
path: '*',
layout: false,
component: './404',
},
];

14
docker/docker-compose.dev.yml

@ -1,14 +0,0 @@
version: '3.5'
services:
ant-design-pro_dev:
ports:
- 8000:8000
build:
context: ../
dockerfile: Dockerfile.dev
container_name: 'ant-design-pro_dev'
volumes:
- ../src:/usr/src/app/src
- ../config:/usr/src/app/config
- ../mock:/usr/src/app/mock

21
docker/docker-compose.yml

@ -1,21 +0,0 @@
version: '3.5'
services:
ant-design-pro_build:
build: ../
container_name: 'ant-design-pro_build'
volumes:
- dist:/usr/src/app/dist
ant-design-pro_web:
image: nginx
ports:
- 80:80
container_name: 'ant-design-pro_web'
restart: unless-stopped
volumes:
- dist:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf
volumes:
dist:

21
docker/nginx.conf

@ -1,21 +0,0 @@
server {
listen 80;
# gzip config
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
root /usr/share/nginx/html;
include /etc/nginx/mime.types;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass https://proapi.azurewebsites.net;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
}

9
jest.config.js

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

23
jest.config.ts

@ -0,0 +1,23 @@
import { configUmiAlias, createConfig } from '@umijs/max/test';
export default async () => {
const config = await configUmiAlias({
...createConfig({
target: 'browser',
}),
});
console.log();
return {
...config,
testEnvironmentOptions: {
...(config?.testEnvironmentOptions || {}),
url: 'http://localhost:8000',
},
setupFiles: [...(config.setupFiles || []), './tests/setupTests.jsx'],
globals: {
...config.globals,
localStorage: null,
},
};
};

10
mock/listTableList.ts

@ -52,16 +52,18 @@ function getRule(req: Request, res: Response, u: string) {
const sorter = JSON.parse(params.sorter);
dataSource = dataSource.sort((prev, next) => {
let sortNumber = 0;
Object.keys(sorter).forEach((key) => {
(Object.keys(sorter) as Array<keyof API.RuleListItem>).forEach((key) => {
let nextSort = next?.[key] as number;
let preSort = prev?.[key] as number;
if (sorter[key] === 'descend') {
if (prev[key] - next[key] > 0) {
if (preSort - nextSort > 0) {
sortNumber += -1;
} else {
sortNumber += 1;
}
return;
}
if (prev[key] - next[key] > 0) {
if (preSort - nextSort > 0) {
sortNumber += 1;
} else {
sortNumber += -1;
@ -76,7 +78,7 @@ function getRule(req: Request, res: Response, u: string) {
};
if (Object.keys(filter).length > 0) {
dataSource = dataSource.filter((item) => {
return Object.keys(filter).some((key) => {
return (Object.keys(filter) as Array<keyof API.RuleListItem>).some((key) => {
if (!filter[key]) {
return true;
}

24
mock/notices.ts

@ -5,21 +5,24 @@ const getNotices = (req: Request, res: Response) => {
data: [
{
id: '000000001',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
avatar:
'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/MSbDR4FR2MUAAAAAAAAAAAAAFl94AQBr',
title: '你收到了 14 份新周报',
datetime: '2017-08-09',
type: 'notification',
},
{
id: '000000002',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png',
avatar:
'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/hX-PTavYIq4AAAAAAAAAAAAAFl94AQBr',
title: '你推荐的 曲妮妮 已通过第三轮面试',
datetime: '2017-08-08',
type: 'notification',
},
{
id: '000000003',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png',
avatar:
'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/jHX5R5l3QjQAAAAAAAAAAAAAFl94AQBr',
title: '这种模板可以区分多种通知类型',
datetime: '2017-08-07',
read: true,
@ -27,21 +30,24 @@ const getNotices = (req: Request, res: Response) => {
},
{
id: '000000004',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png',
avatar:
'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/Wr4mQqx6jfwAAAAAAAAAAAAAFl94AQBr',
title: '左侧图标用于区分不同的类型',
datetime: '2017-08-07',
type: 'notification',
},
{
id: '000000005',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png',
avatar:
'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/Mzj_TbcWUj4AAAAAAAAAAAAAFl94AQBr',
title: '内容不要超过两行字,超出时自动截断',
datetime: '2017-08-07',
type: 'notification',
},
{
id: '000000006',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
avatar:
'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/eXLzRbPqQE4AAAAAAAAAAAAAFl94AQBr',
title: '曲丽丽 评论了你',
description: '描述信息描述信息描述信息',
datetime: '2017-08-07',
@ -50,7 +56,8 @@ const getNotices = (req: Request, res: Response) => {
},
{
id: '000000007',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
avatar:
'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/w5mRQY2AmEEAAAAAAAAAAAAAFl94AQBr',
title: '朱偏右 回复了你',
description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
datetime: '2017-08-07',
@ -59,7 +66,8 @@ const getNotices = (req: Request, res: Response) => {
},
{
id: '000000008',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg',
avatar:
'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/wPadR5M9918AAAAAAAAAAAAAFl94AQBr',
title: '标题',
description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像',
datetime: '2017-08-07',

324
mock/requestRecord.mock.js

@ -0,0 +1,324 @@
module.exports = {
'GET /api/currentUser': {
data: {
name: 'Serati Ma',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/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',
geographic: {
province: { label: '浙江省', key: '330000' },
city: { label: '杭州市', key: '330100' },
},
address: '西湖区工专路 77 号',
phone: '0752-268888888',
},
},
'GET /api/rule': {
data: [
{
key: 99,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 99',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 503,
status: '0',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 81,
},
{
key: 98,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 98',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 164,
status: '0',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 12,
},
{
key: 97,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 97',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 174,
status: '1',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 81,
},
{
key: 96,
disabled: true,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 96',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 914,
status: '0',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 7,
},
{
key: 95,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 95',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 698,
status: '2',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 82,
},
{
key: 94,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 94',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 488,
status: '1',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 14,
},
{
key: 93,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 93',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 580,
status: '2',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 77,
},
{
key: 92,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 92',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 244,
status: '3',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 58,
},
{
key: 91,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 91',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 959,
status: '0',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 66,
},
{
key: 90,
disabled: true,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 90',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 958,
status: '0',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 72,
},
{
key: 89,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 89',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 301,
status: '2',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 2,
},
{
key: 88,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 88',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 277,
status: '1',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 12,
},
{
key: 87,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 87',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 810,
status: '1',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 82,
},
{
key: 86,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 86',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 780,
status: '3',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 22,
},
{
key: 85,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 85',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 705,
status: '3',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 12,
},
{
key: 84,
disabled: true,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 84',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 203,
status: '0',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 79,
},
{
key: 83,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 83',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 491,
status: '2',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 59,
},
{
key: 82,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 82',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 73,
status: '0',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 100,
},
{
key: 81,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png',
name: 'TradeCode 81',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 406,
status: '3',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 61,
},
{
key: 80,
disabled: false,
href: 'https://ant.design',
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png',
name: 'TradeCode 80',
owner: '曲丽丽',
desc: '这是一段描述',
callNo: 112,
status: '2',
updatedAt: '2022-12-06T05:00:57.040Z',
createdAt: '2022-12-06T05:00:57.040Z',
progress: 20,
},
],
total: 100,
success: true,
pageSize: 20,
current: 1,
},
'POST /api/login/outLogin': { data: {}, success: true },
'POST /api/login/account': {
status: 'ok',
type: 'account',
currentAuthority: 'admin',
},
};

138
package.json

@ -1,48 +1,40 @@
{
"name": "ant-design-pro",
"version": "5.2.0",
"version": "6.0.0",
"private": true,
"description": "An out-of-box UI solution for enterprise applications",
"scripts": {
"analyze": "cross-env ANALYZE=1 umi build",
"build": "umi build",
"analyze": "cross-env ANALYZE=1 max build",
"build": "max build",
"deploy": "npm run build && npm run gh-pages",
"dev": "npm run start:dev",
"docker-hub:build": "docker build -f Dockerfile.hub -t ant-design-pro ./",
"docker-prod:build": "docker-compose -f ./docker/docker-compose.yml build",
"docker-prod:dev": "docker-compose -f ./docker/docker-compose.yml up",
"docker:build": "docker-compose -f ./docker/docker-compose.dev.yml build",
"docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up",
"docker:push": "npm run docker-hub:build && npm run docker:tag && docker push antdesign/ant-design-pro",
"docker:tag": "docker tag ant-design-pro antdesign/ant-design-pro",
"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",
"postinstall": "max setup",
"jest": "jest",
"lint": "npm run lint:js && 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:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src ",
"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",
"lint:prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\" --end-of-line auto",
"openapi": "max openapi",
"prepare": "husky install",
"prettier": "prettier -c --write \"src/**/*\"",
"prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\"",
"preview": "npm run build && max preview --port 8000",
"record": "cross-env NODE_ENV=development REACT_APP_ENV=test max record --scene=login",
"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",
"start": "cross-env UMI_ENV=dev max dev",
"start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev",
"start:no-mock": "cross-env MOCK=none UMI_ENV=dev max dev",
"start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev",
"start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev",
"test": "jest",
"test:coverage": "npm run jest -- --coverage",
"test:update": "npm run jest -- -u",
"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"
@ -55,73 +47,65 @@
],
"dependencies": {
"@ant-design/charts": "^0.9.4",
"@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",
"@ant-design/icons": "^4.8.0",
"@ant-design/pro-components": "^2.3.57",
"@ant-design/use-emotion-css": "1.0.4",
"@antv/data-set": "^0.11.0",
"@antv/l7": "^2.3.7",
"@antv/l7-maps": "^2.3.7",
"@antv/l7-react": "^2.1.9",
"@umijs/route-utils": "^2.0.0",
"@umijs/route-utils": "^2.2.2",
"ahooks": "^2.0.0",
"antd": "^4.19.0",
"antd": "^5.2.2",
"antd-style": "^2.0.2",
"bizcharts": "^3.5.3-beta.0",
"bizcharts-plugin-slider": "^2.1.1-beta.1",
"classnames": "^2.3.0",
"classnames": "^2.3.2",
"gg-editor": "^2.0.2",
"lodash": "^4.17.0",
"lodash": "^4.17.21",
"lodash-decorators": "^6.0.0",
"moment": "^2.29.0",
"moment": "^2.29.4",
"numeral": "^2.0.6",
"nzh": "^1.0.3",
"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",
"rc-menu": "^9.8.2",
"rc-util": "^5.27.2",
"react": "^18.2.0",
"react-dev-inspector": "^1.8.4",
"react-dom": "^18.2.0",
"react-fittext": "^1.0.0",
"react-helmet-async": "^1.2.0",
"react-router": "^4.3.1",
"umi": "^3.5.0",
"umi-serve": "^1.9.10"
"react-helmet-async": "^1.3.0",
"react-router": "^4.3.1"
},
"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",
"@ant-design/pro-cli": "^2.1.5",
"@testing-library/react": "^13.4.0",
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
"@types/classnames": "^2.3.1",
"@types/express": "^4.17.17",
"@types/history": "^4.7.11",
"@types/jest": "^29.4.0",
"@types/lodash": "^4.14.191",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/react-helmet": "^6.1.6",
"@umijs/fabric": "^2.14.1",
"@umijs/lint": "^4.0.52",
"@umijs/max": "^4.0.52",
"cross-env": "^7.0.3",
"eslint": "^8.34.0",
"express": "^4.18.2",
"gh-pages": "^3.2.3",
"husky": "^7.0.4",
"jsdom-global": "^3.0.0",
"lint-staged": "^10.0.0",
"jest": "^29.4.3",
"jest-environment-jsdom": "^29.4.3",
"lint-staged": "^10.5.4",
"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"
"prettier": "^2.8.4",
"swagger-ui-dist": "^4.15.5",
"ts-node": "^10.9.1",
"typescript": "^4.9.5",
"umi-presets-pro": "^2.0.2"
},
"engines": {
"node": ">=12.0.0"

22
playwright.config.ts

@ -1,22 +0,0 @@
// 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;

18934
pnpm-lock.yaml

File diff suppressed because it is too large

128
src/pages/document.ejs → public/scripts/loading.js

@ -1,43 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="theme-color" content="#1890ff" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="keywords"
content="antd,umi,umijs,ant design,Scaffolding, layout, Ant Design, project, Pro, admin, console, homepage, out-of-the-box, middle and back office, solution, component library"
/>
<meta
name="description"
content="
An out-of-box UI solution for enterprise applications as a React boilerplate."
/>
<meta
name="description"
content="
Out-of-the-box mid-stage front-end/design solution."
/>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
/>
<title>Ant Design Pro</title>
<link rel="icon" href="<%= context.config.publicPath +'favicon.ico'%>" type="image/x-icon" />
</head>
<body>
<noscript>
<div class="noscript-container">
Hi there! Please
<div class="noscript-enableJS">
<a href="https://www.enablejavascript.io/en" target="_blank" rel="noopener noreferrer">
<b>enable Javascript</b>
</a>
</div>
in your browser to use Ant Design, Out-of-the-box mid-stage front/design solution!
</div>
</noscript>
<div id="root">
/**
* loading 占位
* 解决首次加载时白屏的问题
*/
(function () {
const _root = document.querySelector('#root');
if (_root && _root.innerHTML === '') {
_root.innerHTML = `
<style>
html,
body,
@ -50,24 +18,22 @@
background-repeat: no-repeat;
background-size: 100% auto;
}
.noscript-container {
display: flex;
align-content: center;
justify-content: center;
margin-top: 90px;
font-size: 20px;
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode',
Geneva, Verdana, sans-serif;
.loading-title {
font-size: 1.1rem;
}
.noscript-enableJS {
padding-right: 3px;
padding-left: 3px;
.loading-sub-title {
margin-top: 20px;
font-size: 1rem;
color: #888;
}
.page-loading-warp {
display: flex;
align-items: center;
justify-content: center;
padding: 98px;
padding: 26px;
}
.ant-spin {
position: absolute;
@ -84,13 +50,15 @@
text-align: center;
list-style: none;
opacity: 0;
-webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
-webkit-transition: -webkit-transform 0.3s
cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: -webkit-transform 0.3s
cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
-webkit-font-feature-settings: 'tnum';
font-feature-settings: 'tnum';
-webkit-font-feature-settings: "tnum";
font-feature-settings: "tnum";
}
.ant-spin-spinning {
@ -203,34 +171,32 @@
}
}
</style>
<div
style="
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 420px;
"
>
<img src="<%= context.config.publicPath +'pro_icon.svg'%>" alt="logo" width="256" />
<div style="
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 362px;
">
<div class="page-loading-warp">
<div class="ant-spin ant-spin-lg ant-spin-spinning">
<span class="ant-spin-dot ant-spin-dot-spin"
><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
><i class="ant-spin-dot-item"></i><i class="ant-spin-dot-item"></i
></span>
<span class="ant-spin-dot ant-spin-dot-spin">
<i class="ant-spin-dot-item"></i>
<i class="ant-spin-dot-item"></i>
<i class="ant-spin-dot-item"></i>
<i class="ant-spin-dot-item"></i>
</span>
</div>
</div>
<div style="display: flex; align-items: center; justify-content: center">
<img
src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
width="32"
style="margin-right: 8px"
/>
Ant Design
<div class="loading-title">
正在加载资源
</div>
<div class="loading-sub-title">
初次加载资源可能需要较多时间 请耐心等待
</div>
</div>
</div>
</body>
</html>
`;
}
})();

104
src/app.tsx

@ -1,22 +1,18 @@
import type { Settings as LayoutSettings } from '@ant-design/pro-layout';
import { SettingDrawer } from '@ant-design/pro-layout';
import { PageLoading } from '@ant-design/pro-layout';
import type { RunTimeLayoutConfig } from 'umi';
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 { Question, SelectLang } from '@/components/RightContent';
import { LinkOutlined } from '@ant-design/icons';
import type { Settings as LayoutSettings } from '@ant-design/pro-components';
import { SettingDrawer } from '@ant-design/pro-components';
import type { RunTimeLayoutConfig } from '@umijs/max';
import { history, Link } from '@umijs/max';
import defaultSettings from '../config/defaultSettings';
import { errorConfig } from './requestErrorConfig';
import { currentUser as queryCurrentUser } from './services/ant-design-pro/api';
import React from 'react';
import { AvatarDropdown, AvatarName } from './components/RightContent/AvatarDropdown';
const isDev = process.env.NODE_ENV === 'development';
const loginPath = '/user/login';
/** 获取用户信息比较慢的时候会展示一个 loading */
export const initialStateConfig = {
loading: <PageLoading />,
};
/**
* @see https://umijs.org/zh-CN/plugins/plugin-initial-state
* */
@ -28,7 +24,9 @@ export async function getInitialState(): Promise<{
}> {
const fetchUserInfo = async () => {
try {
const msg = await queryCurrentUser();
const msg = await queryCurrentUser({
skipErrorHandler: true,
});
return msg.data;
} catch (error) {
history.push(loginPath);
@ -36,25 +34,32 @@ export async function getInitialState(): Promise<{
return undefined;
};
// 如果不是登录页面,执行
if (history.location.pathname !== loginPath) {
const { location } = history;
if (location.pathname !== loginPath) {
const currentUser = await fetchUserInfo();
return {
fetchUserInfo,
currentUser,
settings: defaultSettings,
settings: defaultSettings as Partial<LayoutSettings>,
};
}
return {
fetchUserInfo,
settings: defaultSettings,
settings: defaultSettings as Partial<LayoutSettings>,
};
}
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
return {
rightContentRender: () => <RightContent />,
disableContentMargin: false,
actionsRender: () => [<Question key="doc" />, <SelectLang key="SelectLang" />],
avatarProps: {
src: initialState?.currentUser?.avatar,
title: <AvatarName />,
render: (_, avatarChildren) => {
return <AvatarDropdown>{avatarChildren}</AvatarDropdown>;
},
},
waterMarkProps: {
content: initialState?.currentUser?.name,
},
@ -66,43 +71,66 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
history.push(loginPath);
}
},
layoutBgImgList: [
{
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/D2LWSqNny4sAAAAAAAAAAAAAFl94AQBr',
left: 85,
bottom: 100,
height: '303px',
},
{
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/C2TWRpJpiC0AAAAAAAAAAAAAFl94AQBr',
bottom: -68,
right: -45,
height: '303px',
},
{
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/F6vSTbj8KpYAAAAAAAAAAAAAFl94AQBr',
bottom: 0,
left: 0,
width: '331px',
},
],
links: isDev
? [
<Link key="openapi" to="/umi/plugin/openapi" target="_blank">
<LinkOutlined />
<span>OpenAPI </span>
</Link>,
<Link to="/~docs" key="docs">
<BookOutlined />
<span></span>
</Link>,
]
: [],
menuHeaderRender: undefined,
// 自定义 403 页面
// unAccessible: <div>unAccessible</div>,
// 增加一个 loading 的状态
childrenRender: (children, props) => {
childrenRender: (children) => {
// if (initialState?.loading) return <PageLoading />;
return (
<>
{children}
{!props.location?.pathname?.includes('/login') && (
<SettingDrawer
disableUrlParams
enableDarkTheme
settings={initialState?.settings}
onSettingChange={(settings) => {
setInitialState((preInitialState) => ({
...preInitialState,
settings,
}));
}}
/>
)}
<SettingDrawer
disableUrlParams
enableDarkTheme
settings={initialState?.settings}
onSettingChange={(settings) => {
setInitialState((preInitialState) => ({
...preInitialState,
settings,
}));
}}
/>
</>
);
},
...initialState?.settings,
};
};
/**
* @name request
* axios ahooks useRequest
* @doc https://umijs.org/docs/max/request#配置
*/
export const request = {
...errorConfig,
};

8
src/components/Footer/index.tsx

@ -1,6 +1,7 @@
import { useIntl } from 'umi';
import { GithubOutlined } from '@ant-design/icons';
import { DefaultFooter } from '@ant-design/pro-layout';
import { DefaultFooter } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import React from 'react';
const Footer: React.FC = () => {
const intl = useIntl();
@ -13,6 +14,9 @@ const Footer: React.FC = () => {
return (
<DefaultFooter
style={{
background: 'none',
}}
copyright={`${currentYear} ${defaultMessage}`}
links={[
{

16
src/components/HeaderDropdown/index.less

@ -1,16 +0,0 @@
@import (reference) '~antd/es/style/themes/index';
.container > * {
background-color: @popover-bg;
border-radius: 4px;
box-shadow: @shadow-1-down;
}
@media screen and (max-width: @screen-xs) {
.container {
width: 100% !important;
}
.container > * {
border-radius: 0 !important;
}
}

18
src/components/HeaderDropdown/index.tsx

@ -1,17 +1,23 @@
import type { DropDownProps } from 'antd/es/dropdown';
import { Dropdown } from 'antd';
import type { DropDownProps } from 'antd/es/dropdown';
import React from 'react';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import classNames from 'classnames';
import styles from './index.less';
export type HeaderDropdownProps = {
overlayClassName?: string;
overlay: React.ReactNode | (() => React.ReactNode) | any;
placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter';
} & Omit<DropDownProps, 'overlay'>;
const HeaderDropdown: React.FC<HeaderDropdownProps> = ({ overlayClassName: cls, ...restProps }) => (
<Dropdown overlayClassName={classNames(styles.container, cls)} {...restProps} />
);
const HeaderDropdown: React.FC<HeaderDropdownProps> = ({ overlayClassName: cls, ...restProps }) => {
const className = useEmotionCss(({ token }) => {
return {
[`@media screen and (max-width: ${token.screenXS})`]: {
width: '100%',
},
};
});
return <Dropdown overlayClassName={classNames(className, cls)} {...restProps} />;
};
export default HeaderDropdown;

25
src/components/HeaderSearch/index.less

@ -1,25 +0,0 @@
@import (reference) '~antd/es/style/themes/index';
.headerSearch {
display: inline-flex;
align-items: center;
.input {
width: 0;
min-width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
transition: width 0.3s, margin-left 0.3s;
:global(.ant-select-selection) {
background: transparent;
}
input {
box-shadow: none !important;
}
&.show {
width: 210px;
margin-left: 8px;
}
}
}

102
src/components/HeaderSearch/index.tsx

@ -1,102 +0,0 @@
import { SearchOutlined } from '@ant-design/icons';
import type { InputRef } from 'antd';
import { AutoComplete, Input } from 'antd';
import useMergedState from 'rc-util/es/hooks/useMergedState';
import type { AutoCompleteProps } from 'antd/es/auto-complete';
import React, { useRef } from 'react';
import classNames from 'classnames';
import styles from './index.less';
export type HeaderSearchProps = {
onSearch?: (value?: string) => void;
onChange?: (value?: string) => void;
onVisibleChange?: (b: boolean) => void;
className?: string;
placeholder?: string;
options: AutoCompleteProps['options'];
defaultVisible?: boolean;
visible?: boolean;
defaultValue?: string;
value?: string;
};
const HeaderSearch: React.FC<HeaderSearchProps> = (props) => {
const {
className,
defaultValue,
onVisibleChange,
placeholder,
visible,
defaultVisible,
...restProps
} = props;
const inputRef = useRef<InputRef | null>(null);
const [value, setValue] = useMergedState<string | undefined>(defaultValue, {
value: props.value,
onChange: props.onChange,
});
const [searchMode, setSearchMode] = useMergedState(defaultVisible ?? false, {
value: props.visible,
onChange: onVisibleChange,
});
const inputClass = classNames(styles.input, {
[styles.show]: searchMode,
});
return (
<div
className={classNames(className, styles.headerSearch)}
onClick={() => {
setSearchMode(true);
if (searchMode && inputRef.current) {
inputRef.current.focus();
}
}}
onTransitionEnd={({ propertyName }) => {
if (propertyName === 'width' && !searchMode) {
if (onVisibleChange) {
onVisibleChange(searchMode);
}
}
}}
>
<SearchOutlined
key="Icon"
style={{
cursor: 'pointer',
}}
/>
<AutoComplete
key="AutoComplete"
className={inputClass}
value={value}
options={restProps.options}
onChange={(completeValue) => setValue(completeValue)}
>
<Input
size="small"
ref={inputRef}
defaultValue={defaultValue}
aria-label={placeholder}
placeholder={placeholder}
onKeyDown={(e) => {
if (e.key === 'Enter') {
if (restProps.onSearch) {
restProps.onSearch(value);
}
}
}}
onBlur={() => {
setSearchMode(false);
}}
/>
</AutoComplete>
</div>
);
};
export default HeaderSearch;

126
src/components/NoticeIcon/NoticeIcon.tsx

@ -1,126 +0,0 @@
import { BellOutlined } from '@ant-design/icons';
import { Badge, Spin, Tabs } from 'antd';
import useMergedState from 'rc-util/es/hooks/useMergedState';
import React from 'react';
import classNames from 'classnames';
import type { NoticeIconTabProps } from './NoticeList';
import NoticeList from './NoticeList';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
const { TabPane } = Tabs;
export type NoticeIconProps = {
count?: number;
bell?: React.ReactNode;
className?: string;
loading?: boolean;
onClear?: (tabName: string, tabKey: string) => void;
onItemClick?: (item: API.NoticeIconItem, tabProps: NoticeIconTabProps) => void;
onViewMore?: (tabProps: NoticeIconTabProps, e: MouseEvent) => void;
onTabChange?: (tabTile: string) => void;
style?: React.CSSProperties;
onPopupVisibleChange?: (visible: boolean) => void;
popupVisible?: boolean;
clearText?: string;
viewMoreText?: string;
clearClose?: boolean;
emptyImage?: string;
children?: React.ReactElement<NoticeIconTabProps>[];
};
const NoticeIcon: React.FC<NoticeIconProps> & {
Tab: typeof NoticeList;
} = (props) => {
const getNotificationBox = (): React.ReactNode => {
const {
children,
loading,
onClear,
onTabChange,
onItemClick,
onViewMore,
clearText,
viewMoreText,
} = props;
if (!children) {
return null;
}
const panes: React.ReactNode[] = [];
React.Children.forEach(children, (child: React.ReactElement<NoticeIconTabProps>): void => {
if (!child) {
return;
}
const { list, title, count, tabKey, showClear, showViewMore } = child.props;
const len = list && list.length ? list.length : 0;
const msgCount = count || count === 0 ? count : len;
const tabTitle: string = msgCount > 0 ? `${title} (${msgCount})` : title;
panes.push(
<TabPane tab={tabTitle} key={tabKey}>
<NoticeList
clearText={clearText}
viewMoreText={viewMoreText}
list={list}
tabKey={tabKey}
onClear={(): void => onClear && onClear(title, tabKey)}
onClick={(item): void => onItemClick && onItemClick(item, child.props)}
onViewMore={(event): void => onViewMore && onViewMore(child.props, event)}
showClear={showClear}
showViewMore={showViewMore}
title={title}
/>
</TabPane>,
);
});
return (
<>
<Spin spinning={loading} delay={300}>
<Tabs className={styles.tabs} onChange={onTabChange}>
{panes}
</Tabs>
</Spin>
</>
);
};
const { className, count, bell } = props;
const [visible, setVisible] = useMergedState<boolean>(false, {
value: props.popupVisible,
onChange: props.onPopupVisibleChange,
});
const noticeButtonClass = classNames(className, styles.noticeButton);
const notificationBox = getNotificationBox();
const NoticeBellIcon = bell || <BellOutlined className={styles.icon} />;
const trigger = (
<span className={classNames(noticeButtonClass, { opened: visible })}>
<Badge count={count} style={{ boxShadow: 'none' }} className={styles.badge}>
{NoticeBellIcon}
</Badge>
</span>
);
if (!notificationBox) {
return trigger;
}
return (
<HeaderDropdown
placement="bottomRight"
overlay={notificationBox}
overlayClassName={styles.popover}
trigger={['click']}
visible={visible}
onVisibleChange={setVisible}
>
{trigger}
</HeaderDropdown>
);
};
NoticeIcon.defaultProps = {
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
};
NoticeIcon.Tab = NoticeList;
export default NoticeIcon;

103
src/components/NoticeIcon/NoticeList.less

@ -1,103 +0,0 @@
@import (reference) '~antd/es/style/themes/index';
.list {
max-height: 400px;
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
.item {
padding-right: 24px;
padding-left: 24px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s;
.meta {
width: 100%;
}
.avatar {
margin-top: 4px;
background: @component-background;
}
.iconElement {
font-size: 32px;
}
&.read {
opacity: 0.4;
}
&:last-child {
border-bottom: 0;
}
&:hover {
background: @primary-1;
}
.title {
margin-bottom: 8px;
font-weight: normal;
}
.description {
font-size: 12px;
line-height: @line-height-base;
}
.datetime {
margin-top: 4px;
font-size: 12px;
line-height: @line-height-base;
}
.extra {
float: right;
margin-top: -1.5px;
margin-right: 0;
color: @text-color-secondary;
font-weight: normal;
}
}
.loadMore {
padding: 8px 0;
color: @primary-6;
text-align: center;
cursor: pointer;
&.loadedAll {
color: rgba(0, 0, 0, 0.25);
cursor: unset;
}
}
}
.notFound {
padding: 73px 0 88px;
color: @text-color-secondary;
text-align: center;
img {
display: inline-block;
height: 76px;
margin-bottom: 16px;
}
}
.bottomBar {
height: 46px;
color: @text-color;
line-height: 46px;
text-align: center;
border-top: 1px solid @border-color-split;
border-radius: 0 0 @border-radius-base @border-radius-base;
transition: all 0.3s;
div {
display: inline-block;
width: 50%;
cursor: pointer;
transition: all 0.3s;
user-select: none;
&:only-child {
width: 100%;
}
&:not(:only-child):last-child {
border-left: 1px solid @border-color-split;
}
}
}

113
src/components/NoticeIcon/NoticeList.tsx

@ -1,113 +0,0 @@
import { Avatar, List } from 'antd';
import React from 'react';
import classNames from 'classnames';
import styles from './NoticeList.less';
export type NoticeIconTabProps = {
count?: number;
showClear?: boolean;
showViewMore?: boolean;
style?: React.CSSProperties;
title: string;
tabKey: API.NoticeIconItemType;
onClick?: (item: API.NoticeIconItem) => void;
onClear?: () => void;
emptyText?: string;
clearText?: string;
viewMoreText?: string;
list: API.NoticeIconItem[];
onViewMore?: (e: any) => void;
};
const NoticeList: React.FC<NoticeIconTabProps> = ({
list = [],
onClick,
onClear,
title,
onViewMore,
emptyText,
showClear = true,
clearText,
viewMoreText,
showViewMore = false,
}) => {
if (!list || list.length === 0) {
return (
<div className={styles.notFound}>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
alt="not found"
/>
<div>{emptyText}</div>
</div>
);
}
return (
<div>
<List<API.NoticeIconItem>
className={styles.list}
dataSource={list}
renderItem={(item, i) => {
const itemCls = classNames(styles.item, {
[styles.read]: item.read,
});
// eslint-disable-next-line no-nested-ternary
const leftIcon = item.avatar ? (
typeof item.avatar === 'string' ? (
<Avatar className={styles.avatar} src={item.avatar} />
) : (
<span className={styles.iconElement}>{item.avatar}</span>
)
) : null;
return (
<List.Item
className={itemCls}
key={item.key || i}
onClick={() => {
onClick?.(item);
}}
>
<List.Item.Meta
className={styles.meta}
avatar={leftIcon}
title={
<div className={styles.title}>
{item.title}
<div className={styles.extra}>{item.extra}</div>
</div>
}
description={
<div>
<div className={styles.description}>{item.description}</div>
<div className={styles.datetime}>{item.datetime}</div>
</div>
}
/>
</List.Item>
);
}}
/>
<div className={styles.bottomBar}>
{showClear ? (
<div onClick={onClear}>
{clearText} {title}
</div>
) : null}
{showViewMore ? (
<div
onClick={(e) => {
if (onViewMore) {
onViewMore(e);
}
}}
>
{viewMoreText}
</div>
) : null}
</div>
</div>
);
};
export default NoticeList;

35
src/components/NoticeIcon/index.less

@ -1,35 +0,0 @@
@import (reference) '~antd/es/style/themes/index';
.popover {
position: relative;
width: 336px;
}
.noticeButton {
display: inline-block;
cursor: pointer;
transition: all 0.3s;
}
.icon {
padding: 4px;
vertical-align: middle;
}
.badge {
font-size: 16px;
}
.tabs {
:global {
.ant-tabs-nav-list {
margin: auto;
}
.ant-tabs-nav-scroll {
text-align: center;
}
.ant-tabs-nav {
margin-bottom: 0;
}
}
}

153
src/components/NoticeIcon/index.tsx

@ -1,153 +0,0 @@
import { useEffect, useState } from 'react';
import { Tag, message } from 'antd';
import { groupBy } from 'lodash';
import moment from 'moment';
import { useModel, useRequest } from 'umi';
import { getNotices } from '@/services/ant-design-pro/api';
import NoticeIcon from './NoticeIcon';
import styles from './index.less';
export type GlobalHeaderRightProps = {
fetchingNotices?: boolean;
onNoticeVisibleChange?: (visible: boolean) => void;
onNoticeClear?: (tabName?: string) => void;
};
const getNoticeData = (notices: API.NoticeIconItem[]): Record<string, API.NoticeIconItem[]> => {
if (!notices || notices.length === 0 || !Array.isArray(notices)) {
return {};
}
const newNotices = notices.map((notice) => {
const newNotice = { ...notice };
if (newNotice.datetime) {
newNotice.datetime = moment(notice.datetime as string).fromNow();
}
if (newNotice.id) {
newNotice.key = newNotice.id;
}
if (newNotice.extra && newNotice.status) {
const color = {
todo: '',
processing: 'blue',
urgent: 'red',
doing: 'gold',
}[newNotice.status];
newNotice.extra = (
<Tag
color={color}
style={{
marginRight: 0,
}}
>
{newNotice.extra}
</Tag>
) as any;
}
return newNotice;
});
return groupBy(newNotices, 'type');
};
const getUnreadData = (noticeData: Record<string, API.NoticeIconItem[]>) => {
const unreadMsg: Record<string, number> = {};
Object.keys(noticeData).forEach((key) => {
const value = noticeData[key];
if (!unreadMsg[key]) {
unreadMsg[key] = 0;
}
if (Array.isArray(value)) {
unreadMsg[key] = value.filter((item) => !item.read).length;
}
});
return unreadMsg;
};
const NoticeIconView: React.FC = () => {
const { initialState } = useModel('@@initialState');
const { currentUser } = initialState || {};
const [notices, setNotices] = useState<API.NoticeIconItem[]>([]);
const { data } = useRequest(getNotices);
useEffect(() => {
setNotices(data || []);
}, [data]);
const noticeData = getNoticeData(notices);
const unreadMsg = getUnreadData(noticeData || {});
const changeReadState = (id: string) => {
setNotices(
notices.map((item) => {
const notice = { ...item };
if (notice.id === id) {
notice.read = true;
}
return notice;
}),
);
};
const clearReadState = (title: string, key: string) => {
setNotices(
notices.map((item) => {
const notice = { ...item };
if (notice.type === key) {
notice.read = true;
}
return notice;
}),
);
message.success(`${'清空了'} ${title}`);
};
return (
<NoticeIcon
className={styles.action}
count={currentUser && currentUser.unreadCount}
onItemClick={(item) => {
changeReadState(item.id!);
}}
onClear={(title: string, key: string) => clearReadState(title, key)}
loading={false}
clearText="清空"
viewMoreText="查看更多"
onViewMore={() => message.info('Click on view more')}
clearClose
>
<NoticeIcon.Tab
tabKey="notification"
count={unreadMsg.notification}
list={noticeData.notification}
title="通知"
emptyText="你已查看所有通知"
showViewMore
/>
<NoticeIcon.Tab
tabKey="message"
count={unreadMsg.message}
list={noticeData.message}
title="消息"
emptyText="您已读完所有消息"
showViewMore
/>
<NoticeIcon.Tab
tabKey="event"
title="待办"
emptyText="你已完成所有待办"
count={unreadMsg.event}
list={noticeData.event}
showViewMore
/>
</NoticeIcon>
);
};
export default NoticeIconView;

136
src/components/RightContent/AvatarDropdown.tsx

@ -1,43 +1,69 @@
import React, { useCallback } from 'react';
import { outLogin } from '@/services/ant-design-pro/api';
import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons';
import { Avatar, Menu, Spin } from 'antd';
import { history, useModel } from 'umi';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import { history, useModel } from '@umijs/max';
import { Spin } from 'antd';
import { stringify } from 'querystring';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
import { outLogin } from '@/services/ant-design-pro/api';
import type { MenuInfo } from 'rc-menu/lib/interface';
import React, { useCallback } from 'react';
import { flushSync } from 'react-dom';
import HeaderDropdown from '../HeaderDropdown';
export type GlobalHeaderRightProps = {
menu?: boolean;
children?: React.ReactNode;
};
/**
* 退 url
*/
const loginOut = async () => {
await outLogin();
const { query = {}, search, pathname } = history.location;
const { redirect } = query;
// Note: There may be security issues, please note
if (window.location.pathname !== '/user/login' && !redirect) {
history.replace({
pathname: '/user/login',
search: stringify({
redirect: pathname + search,
}),
});
}
export const AvatarName = () => {
const { initialState } = useModel('@@initialState');
const { currentUser } = initialState || {};
return <span className="anticon">{currentUser?.name}</span>;
};
const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu, children }) => {
/**
* 退 url
*/
const loginOut = async () => {
await outLogin();
const { search, pathname } = window.location;
const urlParams = new URL(window.location.href).searchParams;
/** 此方法会跳转到 redirect 参数所在的位置 */
const redirect = urlParams.get('redirect');
// Note: There may be security issues, please note
if (window.location.pathname !== '/user/login' && !redirect) {
history.replace({
pathname: '/user/login',
search: stringify({
redirect: pathname + search,
}),
});
}
};
const actionClassName = useEmotionCss(({ token }) => {
return {
display: 'flex',
height: '48px',
marginLeft: 'auto',
overflow: 'hidden',
alignItems: 'center',
padding: '0 8px',
cursor: 'pointer',
borderRadius: token.borderRadius,
'&:hover': {
backgroundColor: token.colorBgTextHover,
},
};
});
const { initialState, setInitialState } = useModel('@@initialState');
const onMenuClick = useCallback(
(event: MenuInfo) => {
const { key } = event;
if (key === 'logout') {
setInitialState((s) => ({ ...s, currentUser: undefined }));
flushSync(() => {
setInitialState((s) => ({ ...s, currentUser: undefined }));
});
loginOut();
return;
}
@ -47,7 +73,7 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
);
const loading = (
<span className={`${styles.action} ${styles.account}`}>
<span className={actionClassName}>
<Spin
size="small"
style={{
@ -68,36 +94,40 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
return loading;
}
const menuHeaderDropdown = (
<Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
{menu && (
<Menu.Item key="center">
<UserOutlined />
</Menu.Item>
)}
{menu && (
<Menu.Item key="settings">
<SettingOutlined />
</Menu.Item>
)}
{menu && <Menu.Divider />}
const menuItems = [
...(menu
? [
{
key: 'center',
icon: <UserOutlined />,
label: '个人中心',
},
{
key: 'settings',
icon: <SettingOutlined />,
label: '个人设置',
},
{
type: 'divider' as const,
},
]
: []),
{
key: 'logout',
icon: <LogoutOutlined />,
label: '退出登录',
},
];
<Menu.Item key="logout">
<LogoutOutlined />
退
</Menu.Item>
</Menu>
);
return (
<HeaderDropdown overlay={menuHeaderDropdown}>
<span className={`${styles.action} ${styles.account}`}>
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
<span className={`${styles.name} anticon`}>{currentUser.name}</span>
</span>
<HeaderDropdown
menu={{
selectedKeys: [],
onClick: onMenuClick,
items: menuItems,
}}
>
{children}
</HeaderDropdown>
);
};
export default AvatarDropdown;

84
src/components/RightContent/index.less

@ -1,84 +0,0 @@
@import (reference) '~antd/es/style/themes/index';
@pro-header-hover-bg: rgba(0, 0, 0, 0.025);
.menu {
:global(.anticon) {
margin-right: 8px;
}
:global(.ant-dropdown-menu-item) {
min-width: 160px;
}
}
.right {
display: flex;
float: right;
height: 48px;
margin-left: auto;
overflow: hidden;
.action {
display: flex;
align-items: center;
height: 48px;
padding: 0 12px;
cursor: pointer;
transition: all 0.3s;
> span {
vertical-align: middle;
}
&:hover {
background: @pro-header-hover-bg;
}
&:global(.opened) {
background: @pro-header-hover-bg;
}
}
.search {
padding: 0 12px;
&:hover {
background: transparent;
}
}
.account {
.avatar {
margin-right: 8px;
color: @primary-color;
vertical-align: top;
background: rgba(255, 255, 255, 0.85);
}
}
}
.dark {
.action {
&:hover {
background: #252a3d;
}
&:global(.opened) {
background: #252a3d;
}
}
}
@media only screen and (max-width: @screen-md) {
:global(.ant-divider-vertical) {
vertical-align: unset;
}
.name {
display: none;
}
.right {
position: absolute;
top: 0;
right: 12px;
.account {
.avatar {
margin-right: 0;
}
}
.search {
display: none;
}
}
}

81
src/components/RightContent/index.tsx

@ -1,68 +1,31 @@
import { Space } from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { SelectLang as UmiSelectLang } from '@umijs/max';
import React from 'react';
import { useModel, SelectLang } from 'umi';
import Avatar from './AvatarDropdown';
import HeaderSearch from '../HeaderSearch';
import styles from './index.less';
import NoticeIconView from '../NoticeIcon';
export type SiderTheme = 'light' | 'dark';
const GlobalHeaderRight: React.FC = () => {
const { initialState } = useModel('@@initialState');
if (!initialState || !initialState.settings) {
return null;
}
const { navTheme, layout } = initialState.settings;
let className = styles.right;
if ((navTheme === 'dark' && layout === 'top') || layout === 'mix') {
className = `${styles.right} ${styles.dark}`;
}
export const SelectLang = () => {
return (
<Space className={className}>
<HeaderSearch
className={`${styles.action} ${styles.search}`}
placeholder="站内搜索"
defaultValue="umi ui"
options={[
{
label: <a href="https://umijs.org/zh/guide/umi-ui.html">umi ui</a>,
value: 'umi ui',
},
{
label: <a href="next.ant.design">Ant Design</a>,
value: 'Ant Design',
},
{
label: <a href="https://protable.ant.design/">Pro Table</a>,
value: 'Pro Table',
},
{
label: <a href="https://prolayout.ant.design/">Pro Layout</a>,
value: 'Pro Layout',
},
]} // onSearch={value => {
// console.log('input', value);
// }}
/>
<span
className={styles.action}
onClick={() => {
window.open('https://pro.ant.design/docs/getting-started');
}}
>
<QuestionCircleOutlined />
</span>
<NoticeIconView />
<Avatar menu />
<SelectLang className={styles.action} />
</Space>
<UmiSelectLang
style={{
padding: 4,
}}
/>
);
};
export default GlobalHeaderRight;
export const Question = () => {
return (
<div
style={{
display: 'flex',
height: 26,
}}
onClick={() => {
window.open('https://pro.ant.design/docs/getting-started');
}}
>
<QuestionCircleOutlined />
</div>
);
};

272
src/components/index.md

@ -1,272 +0,0 @@
---
title: 业务组件
sidemenu: false
---
> 此功能由[dumi](https://d.umijs.org/zh-CN/guide/advanced#umi-%E9%A1%B9%E7%9B%AE%E9%9B%86%E6%88%90%E6%A8%A1%E5%BC%8F)提供,dumi 是一个 📖 为组件开发场景而生的文档工具,用过的都说好。
# 业务组件
这里列举了 Pro 中所有用到的组件,这些组件不适合作为组件库,但是在业务中却真实需要。所以我们准备了这个文档,来指导大家是否需要使用这个组件。
## Footer 页脚组件
这个组件自带了一些 Pro 的配置,你一般都需要改掉它的信息。
```tsx
/**
* background: '#f0f2f5'
*/
import React from 'react';
import Footer from '@/components/Footer';
export default () => <Footer />;
```
## HeaderDropdown 头部下拉列表
HeaderDropdown 是 antd Dropdown 的封装,但是增加了移动端的特殊处理,用法也是相同的。
```tsx
/**
* background: '#f0f2f5'
*/
import { Button, Menu } from 'antd';
import React from 'react';
import HeaderDropdown from '@/components/HeaderDropdown';
export default () => {
const menuHeaderDropdown = (
<Menu selectedKeys={[]}>
<Menu.Item key="center">个人中心</Menu.Item>
<Menu.Item key="settings">个人设置</Menu.Item>
<Menu.Divider />
<Menu.Item key="logout">退出登录</Menu.Item>
</Menu>
);
return (
<HeaderDropdown overlay={menuHeaderDropdown}>
<Button>hover 展示菜单</Button>
</HeaderDropdown>
);
};
```
## HeaderSearch 头部搜索框
一个带补全数据的输入框,支持收起和展开 Input
```tsx
/**
* background: '#f0f2f5'
*/
import { Button, Menu } from 'antd';
import React from 'react';
import HeaderSearch from '@/components/HeaderSearch';
export default () => {
return (
<HeaderSearch
placeholder="站内搜索"
defaultValue="umi ui"
options={[
{ label: 'Ant Design Pro', value: 'Ant Design Pro' },
{
label: 'Ant Design',
value: 'Ant Design',
},
{
label: 'Pro Table',
value: 'Pro Table',
},
{
label: 'Pro Layout',
value: 'Pro Layout',
},
]}
onSearch={(value) => {
console.log('input', value);
}}
/>
);
};
```
### API
| 参数 | 说明 | 类型 | 默认值 |
| --------------- | ---------------------------------- | ---------------------------- | ------ |
| value | 输入框的值 | `string` | - |
| onChange | 值修改后触发 | `(value?: string) => void` | - |
| onSearch | 查询后触发 | `(value?: string) => void` | - |
| options | 选项菜单的的列表 | `{label,value}[]` | - |
| defaultVisible | 输入框默认是否显示,只有第一次生效 | `boolean` | - |
| visible | 输入框是否显示 | `boolean` | - |
| onVisibleChange | 输入框显示隐藏的回调函数 | `(visible: boolean) => void` | - |
## NoticeIcon 通知工具
通知工具提供一个展示多种通知信息的界面。
```tsx
/**
* background: '#f0f2f5'
*/
import { message } from 'antd';
import React from 'react';
import NoticeIcon from '@/components/NoticeIcon/NoticeIcon';
export default () => {
const list = [
{
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',
},
];
return (
<NoticeIcon
count={10}
onItemClick={(item) => {
message.info(`${item.title} 被点击了`);
}}
onClear={(title: string, key: string) => message.info('点击了清空更多')}
loading={false}
clearText="清空"
viewMoreText="查看更多"
onViewMore={() => message.info('点击了查看更多')}
clearClose
>
<NoticeIcon.Tab
tabKey="notification"
count={2}
list={list}
title="通知"
emptyText="你已查看所有通知"
showViewMore
/>
<NoticeIcon.Tab
tabKey="message"
count={2}
list={list}
title="消息"
emptyText="您已读完所有消息"
showViewMore
/>
<NoticeIcon.Tab
tabKey="event"
title="待办"
emptyText="你已完成所有待办"
count={2}
list={list}
showViewMore
/>
</NoticeIcon>
);
};
```
### NoticeIcon API
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| count | 有多少未读通知 | `number` | - |
| bell | 铃铛的图表 | `ReactNode` | - |
| onClear | 点击清空数据按钮 | `(tabName: string, tabKey: string) => void` | - |
| onItemClick | 未读消息列被点击 | `(item: API.NoticeIconData, tabProps: NoticeIconTabProps) => void` | - |
| onViewMore | 查看更多的按钮点击 | `(tabProps: NoticeIconTabProps, e: MouseEvent) => void` | - |
| onTabChange | 通知 Tab 的切换 | `(tabTile: string) => void;` | - |
| popupVisible | 通知显示是否展示 | `boolean` | - |
| onPopupVisibleChange | 通知信息显示隐藏的回调函数 | `(visible: boolean) => void` | - |
| clearText | 清空按钮的文字 | `string` | - |
| viewMoreText | 查看更多的按钮文字 | `string` | - |
| clearClose | 展示清空按钮 | `boolean` | - |
| emptyImage | 列表为空时的兜底展示 | `ReactNode` | - |
### NoticeIcon.Tab API
| 参数 | 说明 | 类型 | 默认值 |
| ------------ | ------------------ | ------------------------------------ | ------ |
| count | 有多少未读通知 | `number` | - |
| title | 通知 Tab 的标题 | `ReactNode` | - |
| showClear | 展示清除按钮 | `boolean` | `true` |
| showViewMore | 展示加载更 | `boolean` | `true` |
| tabKey | Tab 的唯一 key | `string` | - |
| onClick | 子项的单击事件 | `(item: API.NoticeIconData) => void` | - |
| onClear | 清楚按钮的点击 | `()=>void` | - |
| emptyText | 为空的时候测试 | `()=>void` | - |
| viewMoreText | 查看更多的按钮文字 | `string` | - |
| onViewMore | 查看更多的按钮点击 | `( e: MouseEvent) => void` | - |
| list | 通知信息的列表 | `API.NoticeIconData` | - |
### NoticeIconData
```tsx | pure
export interface NoticeIconData {
id: string;
key: string;
avatar: string;
title: string;
datetime: string;
type: string;
read?: boolean;
description: string;
clickClose?: boolean;
extra: any;
status: string;
}
```
## RightContent
RightContent 是以上几个组件的组合,同时新增了 plugins 的 `SelectLang` 插件。
```tsx | pure
<Space>
<HeaderSearch
placeholder="站内搜索"
defaultValue="umi ui"
options={[
{ label: <a href="https://umijs.org/zh/guide/umi-ui.html">umi ui</a>, value: 'umi ui' },
{
label: <a href="next.ant.design">Ant Design</a>,
value: 'Ant Design',
},
{
label: <a href="https://protable.ant.design/">Pro Table</a>,
value: 'Pro Table',
},
{
label: <a href="https://prolayout.ant.design/">Pro Layout</a>,
value: 'Pro Layout',
},
]}
/>
<Tooltip title="使用文档">
<span
className={styles.action}
onClick={() => {
window.location.href = 'https://pro.ant.design/docs/getting-started';
}}
>
<QuestionCircleOutlined />
</span>
</Tooltip>
<Avatar />
{REACT_APP_ENV && (
<span>
<Tag color={ENVTagColor[REACT_APP_ENV]}>{REACT_APP_ENV}</Tag>
</span>
)}
<SelectLang className={styles.action} />
</Space>
```

45
src/e2e/baseLayout.e2e.spec.ts

@ -1,45 +0,0 @@
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);
});
});

17
src/global.less

@ -1,11 +1,3 @@
@import '~antd/es/style/variable.less';
html,
body,
#root {
height: 100%;
}
.colorWeak {
filter: invert(80%);
}
@ -32,7 +24,7 @@ ol {
list-style: none;
}
@media (max-width: @screen-xs) {
@media (max-width: 768px) {
.ant-table {
width: 100%;
overflow-x: auto;
@ -48,10 +40,3 @@ ol {
}
}
}
// Compatible with IE11
@media screen and(-ms-high-contrast: active), (-ms-high-contrast: none) {
body .ant-design-pro > .ant-layout {
min-height: 100vh;
}
}

42
src/global.style.ts

@ -0,0 +1,42 @@
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
colorWeak: {
filter: 'invert(80%)',
},
'ant-layout': {
minHeight: '100vh',
},
'ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed': {
left: 'unset',
},
canvas: {
display: 'block',
},
body: {
textRendering: 'optimizeLegibility',
WebkitFontSmoothing: 'antialiased',
MozOsxFontSmoothing: 'grayscale',
},
'ul,ol': {
listStyle: 'none',
},
'@media(max-width: 768px)': {
'ant-table': {
width: '100%',
overflowX: 'auto',
'&-thead > tr, &-tbody > tr': {
'> th, > td': {
whiteSpace: 'pre',
'> span': {
display: 'block',
},
},
},
},
},
};
});
export default useStyles;

4
src/global.tsx

@ -1,5 +1,5 @@
import { useIntl } from '@umijs/max';
import { Button, message, notification } from 'antd';
import { useIntl } from 'umi';
import defaultSettings from '../config/defaultSettings';
const { pwa } = defaultSettings;
@ -58,7 +58,7 @@ if (pwa) {
<Button
type="primary"
onClick={() => {
notification.close(key);
notification.destroy(key);
reloadSW();
}}
>

2
src/locales/bn-BD/pages.ts

@ -23,9 +23,7 @@ export default {
'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': 'এই পৃষ্ঠাটি কেবল অ্যাডমিন দ্বারা দেখা যাবে',
'pages.admin.subPage.alertMessage':

4
src/locales/en-US/pages.ts

@ -23,9 +23,7 @@ export default {
'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':
@ -65,6 +63,6 @@ export default {
'pages.searchTable.item': 'item',
'pages.searchTable.totalServiceCalls': 'Total Number of Service Calls',
'pages.searchTable.tenThousand': '0000',
'pages.searchTable.batchDeletion': 'bacth deletion',
'pages.searchTable.batchDeletion': 'batch deletion',
'pages.searchTable.batchApproval': 'batch approval',
};

2
src/locales/fa-IR.ts

@ -1,10 +1,10 @@
import component from './fa-IR/component';
import globalHeader from './fa-IR/globalHeader';
import menu from './fa-IR/menu';
import pages from './fa-IR/pages';
import pwa from './fa-IR/pwa';
import settingDrawer from './fa-IR/settingDrawer';
import settings from './fa-IR/settings';
import pages from './fa-IR/pages';
export default {
'navBar.lang': 'زبان ها ',

4
src/locales/fa-IR/pages.ts

@ -2,6 +2,8 @@ export default {
'pages.layouts.userLayout.title': 'طراحی مورچه تأثیرگذارترین مشخصات طراحی وب در منطقه Xihu است',
'pages.login.accountLogin.tab': 'ورود به حساب کاربری',
'pages.login.accountLogin.errorMessage': 'نام کاربری / رمزعبور نادرست (مدیر / ant.design)',
'pages.login.failure': 'ورود به سیستم با شکست مواجه شد، لطفا دوباره سعی کنید!',
'pages.login.success': 'ورود موفق!',
'pages.login.username.placeholder': 'نام کاربری: مدیر یا کاربر',
'pages.login.username.required': 'لطفا نام کاربری خود را وارد کنید!',
'pages.login.password.placeholder': 'رمز عبور: ant.design',
@ -20,9 +22,7 @@ export default {
'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': 'این صفحه فقط توسط مدیر قابل مشاهده است',
'pages.admin.subPage.alertMessage':

2
src/locales/id-ID.ts

@ -1,10 +1,10 @@
import component from './id-ID/component';
import globalHeader from './id-ID/globalHeader';
import menu from './id-ID/menu';
import pages from './id-ID/pages';
import pwa from './id-ID/pwa';
import settingDrawer from './id-ID/settingDrawer';
import settings from './id-ID/settings';
import pages from './id-ID/pages';
export default {
'navbar.lang': 'Bahasa',

4
src/locales/id-ID/pages.ts

@ -3,6 +3,8 @@ export default {
'Ant Design adalah spesifikasi desain Web yang paling berpengaruh di Kabupaten Xihu',
'pages.login.accountLogin.tab': 'Login dengan akun',
'pages.login.accountLogin.errorMessage': 'Nama pengguna dan kata sandi salah(admin/ant.design)',
'pages.login.failure': 'Log masuk gagal, silakan coba lagi!',
'pages.login.success': 'Login berhasil!',
'pages.login.username.placeholder': 'nama pengguna: admin atau user',
'pages.login.username.required': 'Nama pengguna harus diisi!',
'pages.login.password.placeholder': 'kata sandi: ant.design',
@ -21,9 +23,7 @@ export default {
'pages.login.submit': 'Masuk',
'pages.login.loginWith': 'Masuk dengan :',
'pages.login.registerAccount': 'Daftar Akun',
'pages.welcome.advancedComponent': 'Formulir Lanjutan',
'pages.welcome.link': 'Selamat datang',
'pages.welcome.advancedLayout': 'Tata letak Lanjutan',
'pages.welcome.alertMessage':
'Komponen heavy-duty yang lebih cepat dan lebih kuat telah dirilis.',
'pages.admin.subPage.title': 'Halaman ini hanya dapat dilihat oleh admin',

6
src/locales/ja-JP.ts

@ -1,10 +1,10 @@
import component from './ja-JP/component';
import globalHeader from './ja-JP/globalHeader';
import menu from './ja-JP/menu';
import pages from './ja-JP/pages';
import pwa from './ja-JP/pwa';
import settingDrawer from './ja-JP/settingDrawer';
import settings from './ja-JP/settings';
import pwa from './ja-JP/pwa';
import component from './ja-JP/component';
import pages from './ja-JP/pages';
export default {
'navBar.lang': '言語',

4
src/locales/ja-JP/pages.ts

@ -3,6 +3,8 @@ export default {
'pages.login.accountLogin.tab': 'アカウントログイン',
'pages.login.accountLogin.errorMessage':
'ユーザー名/パスワードが正しくありません(admin/ant.design)',
'pages.login.failure': 'ログインに失敗したら、もう一度試してください!',
'pages.login.success': 'ログイン成功!',
'pages.login.username.placeholder': 'ユーザー名:adminまたはuser',
'pages.login.username.required': 'ユーザー名を入力してください!',
'pages.login.password.placeholder': 'パスワード:ant.design',
@ -21,9 +23,7 @@ export default {
'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': 'このページは管理者のみが表示できます',
'pages.admin.subPage.alertMessage':

2
src/locales/pt-BR.ts

@ -1,10 +1,10 @@
import component from './pt-BR/component';
import globalHeader from './pt-BR/globalHeader';
import menu from './pt-BR/menu';
import pages from './pt-BR/pages';
import pwa from './pt-BR/pwa';
import settingDrawer from './pt-BR/settingDrawer';
import settings from './pt-BR/settings';
import pages from './pt-BR/pages';
export default {
'navBar.lang': 'Idiomas',

1
src/locales/pt-BR/globalHeader.ts

@ -13,6 +13,5 @@ export default {
'component.noticeIcon.clear': 'Limpar',
'component.noticeIcon.cleared': 'Limpo',
'component.noticeIcon.empty': 'Sem notificações',
'component.noticeIcon.loaded': 'Carregado',
'component.noticeIcon.view-more': 'Veja mais',
};

2
src/locales/pt-BR/menu.ts

@ -2,9 +2,9 @@ export default {
'menu.welcome': 'Welcome',
'menu.more-blocks': 'More Blocks',
'menu.home': 'Início',
'menu.login': 'Login',
'menu.admin': 'Admin',
'menu.admin.sub-page': 'Sub-Page',
'menu.login': 'Login',
'menu.register': 'Registro',
'menu.register-result': 'Resultado de registro',
'menu.dashboard': 'Dashboard',

4
src/locales/pt-BR/pages.ts

@ -3,6 +3,8 @@ export default {
'Ant Design é a especificação de web design mais influente no distrito de Xihu',
'pages.login.accountLogin.tab': 'Login da conta',
'pages.login.accountLogin.errorMessage': 'usuário/senha incorreto(admin/ant.design)',
'pages.login.failure': 'Login falhou, por favor tente novamente!',
'pages.login.success': 'Login efetuado com sucesso!',
'pages.login.username.placeholder': 'Usuário: admin or user',
'pages.login.username.required': 'Por favor insira seu usuário!',
'pages.login.password.placeholder': 'Senha: ant.design',
@ -21,9 +23,7 @@ export default {
'pages.login.submit': 'Enviar',
'pages.login.loginWith': 'Login com :',
'pages.login.registerAccount': 'Registra Conta',
'pages.welcome.advancedComponent': 'Componente Avançado',
'pages.welcome.link': 'Bem-vindo',
'pages.welcome.advancedLayout': 'Layout Avançado',
'pages.welcome.alertMessage': 'Componentes pesados mais rápidos e mais fortes foram lançados.',
'pages.admin.subPage.title': 'Esta página só pode ser vista pelo Admin',
'pages.admin.subPage.alertMessage':

2
src/locales/zh-CN.ts

@ -1,10 +1,10 @@
import component from './zh-CN/component';
import globalHeader from './zh-CN/globalHeader';
import menu from './zh-CN/menu';
import pages from './zh-CN/pages';
import pwa from './zh-CN/pwa';
import settingDrawer from './zh-CN/settingDrawer';
import settings from './zh-CN/settings';
import pages from './zh-CN/pages';
export default {
'navBar.lang': '语言',

2
src/locales/zh-CN/pages.ts

@ -22,9 +22,7 @@ export default {
'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 启动体验。',

18
src/locales/zh-TW/menu.ts

@ -2,18 +2,18 @@ export default {
'menu.welcome': '歡迎',
'menu.more-blocks': '更多區塊',
'menu.home': '首頁',
'menu.login': '登錄',
'menu.admin': '权限',
'menu.admin.sub-page': '二级管理页',
'menu.exception.403': '403',
'menu.exception.404': '404',
'menu.exception.500': '500',
'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': '分步表單',
@ -35,16 +35,16 @@ export default {
'menu.result': '結果頁',
'menu.result.success': '成功頁',
'menu.result.fail': '失敗頁',
'menu.account': '個人頁',
'menu.account.center': '個人中心',
'menu.account.settings': '個人設置',
'menu.account.trigger': '觸發報錯',
'menu.account.logout': '退出登錄',
'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': '腦圖編輯器',

65
src/locales/zh-TW/pages.ts

@ -0,0 +1,65 @@
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.link': '歡迎使用',
'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': '批量審批',
};

2
src/pages/404.tsx

@ -1,6 +1,6 @@
import { history } from '@umijs/max';
import { Button, Result } from 'antd';
import React from 'react';
import { history } from 'umi';
const NoFoundPage: React.FC = () => (
<Result

12
src/pages/Admin.tsx

@ -1,13 +1,13 @@
import React from 'react';
import { HeartTwoTone, SmileTwoTone } from '@ant-design/icons';
import { Card, Typography, Alert } from 'antd';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { useIntl } from 'umi';
import { PageContainer } from '@ant-design/pro-components';
import { useIntl } from '@umijs/max';
import { Alert, Card, Typography } from 'antd';
import React from 'react';
const Admin: React.FC = () => {
const intl = useIntl();
return (
<PageHeaderWrapper
<PageContainer
content={intl.formatMessage({
id: 'pages.admin.subPage.title',
defaultMessage: 'This page can only be viewed by admin',
@ -38,7 +38,7 @@ const Admin: React.FC = () => {
</a>
</p>
</PageHeaderWrapper>
</PageContainer>
);
};

16
src/pages/TableList/components/UpdateForm.tsx

@ -1,14 +1,14 @@
import React from 'react';
import { Modal } from 'antd';
import {
ProFormDateTimePicker,
ProFormRadio,
ProFormSelect,
ProFormText,
ProFormTextArea,
StepsForm,
ProFormRadio,
ProFormDateTimePicker,
} from '@ant-design/pro-form';
import { useIntl, FormattedMessage } from 'umi';
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Modal } from 'antd';
import React from 'react';
export type FormValueType = {
target?: string;
@ -21,7 +21,7 @@ export type FormValueType = {
export type UpdateFormProps = {
onCancel: (flag?: boolean, formVals?: FormValueType) => void;
onSubmit: (values: FormValueType) => Promise<void>;
updateModalVisible: boolean;
updateModalOpen: boolean;
values: Partial<API.RuleListItem>;
};
@ -42,7 +42,7 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => {
id: 'pages.searchTable.updateForm.ruleConfig',
defaultMessage: '规则配置',
})}
visible={props.updateModalVisible}
open={props.updateModalOpen}
footer={submitter}
onCancel={() => {
props.onCancel();

46
src/pages/TableList/index.tsx

@ -1,16 +1,20 @@
import { addRule, removeRule, rule, updateRule } from '@/services/ant-design-pro/api';
import { PlusOutlined } from '@ant-design/icons';
import { Button, message, Input, Drawer } from 'antd';
import React, { useState, useRef } from 'react';
import { useIntl, FormattedMessage } from 'umi';
import { PageContainer, FooterToolbar } from '@ant-design/pro-layout';
import type { ProColumns, ActionType } from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import { ModalForm, ProFormText, ProFormTextArea } from '@ant-design/pro-form';
import type { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
import ProDescriptions from '@ant-design/pro-descriptions';
import type { ActionType, ProColumns, ProDescriptionsItemProps } from '@ant-design/pro-components';
import {
FooterToolbar,
ModalForm,
PageContainer,
ProDescriptions,
ProFormText,
ProFormTextArea,
ProTable,
} from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Button, Drawer, Input, message } from 'antd';
import React, { useRef, useState } from 'react';
import type { FormValueType } from './components/UpdateForm';
import UpdateForm from './components/UpdateForm';
import { rule, addRule, updateRule, removeRule } from '@/services/ant-design-pro/api';
/**
* @en-US Add node
@ -84,12 +88,12 @@ const TableList: React.FC = () => {
* @en-US Pop-up window of new window
* @zh-CN
* */
const [createModalVisible, handleModalVisible] = useState<boolean>(false);
const [createModalOpen, handleModalOpen] = useState<boolean>(false);
/**
* @en-US The pop-up window of the distribution update window
* @zh-CN
* */
const [updateModalVisible, handleUpdateModalVisible] = useState<boolean>(false);
const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);
const [showDetail, setShowDetail] = useState<boolean>(false);
@ -221,7 +225,7 @@ const TableList: React.FC = () => {
<a
key="config"
onClick={() => {
handleUpdateModalVisible(true);
handleUpdateModalOpen(true);
setCurrentRow(record);
}}
>
@ -254,7 +258,7 @@ const TableList: React.FC = () => {
type="primary"
key="primary"
onClick={() => {
handleModalVisible(true);
handleModalOpen(true);
}}
>
<PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="New" />
@ -313,12 +317,12 @@ const TableList: React.FC = () => {
defaultMessage: 'New rule',
})}
width="400px"
visible={createModalVisible}
onVisibleChange={handleModalVisible}
open={createModalOpen}
onOpenChange={handleModalOpen}
onFinish={async (value) => {
const success = await handleAdd(value as API.RuleListItem);
if (success) {
handleModalVisible(false);
handleModalOpen(false);
if (actionRef.current) {
actionRef.current.reload();
}
@ -346,7 +350,7 @@ const TableList: React.FC = () => {
onSubmit={async (value) => {
const success = await handleUpdate(value);
if (success) {
handleUpdateModalVisible(false);
handleUpdateModalOpen(false);
setCurrentRow(undefined);
if (actionRef.current) {
actionRef.current.reload();
@ -354,18 +358,18 @@ const TableList: React.FC = () => {
}
}}
onCancel={() => {
handleUpdateModalVisible(false);
handleUpdateModalOpen(false);
if (!showDetail) {
setCurrentRow(undefined);
}
}}
updateModalVisible={updateModalVisible}
updateModalOpen={updateModalOpen}
values={currentRow || {}}
/>
<Drawer
width={600}
visible={showDetail}
open={showDetail}
onClose={() => {
setCurrentRow(undefined);
setShowDetail(false);

1114
src/pages/User/Login/__snapshots__/login.test.tsx.snap

File diff suppressed because it is too large

193
src/pages/user/Login/index.tsx → src/pages/User/Login/index.tsx

@ -1,3 +1,6 @@
import Footer from '@/components/Footer';
import { login } from '@/services/ant-design-pro/api';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
import {
AlipayCircleOutlined,
LockOutlined,
@ -6,43 +9,108 @@ import {
UserOutlined,
WeiboCircleOutlined,
} from '@ant-design/icons';
import {
LoginForm,
ProFormCaptcha,
ProFormCheckbox,
ProFormText,
} from '@ant-design/pro-components';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import { FormattedMessage, history, SelectLang, useIntl, useModel, Helmet } from '@umijs/max';
import { Alert, message, Tabs } from 'antd';
import Settings from '../../../../config/defaultSettings';
import React, { useState } from 'react';
import { ProFormCaptcha, ProFormCheckbox, ProFormText, LoginForm } from '@ant-design/pro-form';
import { useIntl, history, FormattedMessage, SelectLang, useModel } from 'umi';
import Footer from '@/components/Footer';
import { login } from '@/services/ant-design-pro/api';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
import { flushSync } from 'react-dom';
import styles from './index.less';
const ActionIcons = () => {
const langClassName = useEmotionCss(({ token }) => {
return {
marginLeft: '8px',
color: 'rgba(0, 0, 0, 0.2)',
fontSize: '24px',
verticalAlign: 'middle',
cursor: 'pointer',
transition: 'color 0.3s',
'&:hover': {
color: token.colorPrimaryActive,
},
};
});
return (
<>
<AlipayCircleOutlined key="AlipayCircleOutlined" className={langClassName} />
<TaobaoCircleOutlined key="TaobaoCircleOutlined" className={langClassName} />
<WeiboCircleOutlined key="WeiboCircleOutlined" className={langClassName} />
</>
);
};
const Lang = () => {
const langClassName = useEmotionCss(({ token }) => {
return {
width: 42,
height: 42,
lineHeight: '42px',
position: 'fixed',
right: 16,
borderRadius: token.borderRadius,
':hover': {
backgroundColor: token.colorBgTextHover,
},
};
});
return (
<div className={langClassName} data-lang>
{SelectLang && <SelectLang />}
</div>
);
};
const LoginMessage: React.FC<{
content: string;
}> = ({ content }) => (
<Alert
style={{
marginBottom: 24,
}}
message={content}
type="error"
showIcon
/>
);
}> = ({ content }) => {
return (
<Alert
style={{
marginBottom: 24,
}}
message={content}
type="error"
showIcon
/>
);
};
const Login: React.FC = () => {
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({});
const [type, setType] = useState<string>('account');
const { initialState, setInitialState } = useModel('@@initialState');
const containerClassName = useEmotionCss(() => {
return {
display: 'flex',
flexDirection: 'column',
height: '100vh',
overflow: 'auto',
backgroundImage:
"url('https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/V-_oS6r-i7wAAAAAAAAAAAAAFl94AQBr')",
backgroundSize: '100% 100%',
};
});
const intl = useIntl();
const fetchUserInfo = async () => {
const userInfo = await initialState?.fetchUserInfo?.();
if (userInfo) {
await setInitialState((s) => ({
...s,
currentUser: userInfo,
}));
flushSync(() => {
setInitialState((s) => ({
...s,
currentUser: userInfo,
}));
});
}
};
@ -57,11 +125,8 @@ const Login: React.FC = () => {
});
message.success(defaultLoginSuccessMessage);
await fetchUserInfo();
/** 此方法会跳转到 redirect 参数所在的位置 */
if (!history) return;
const { query } = history.location;
const { redirect } = query as { redirect: string };
history.push(redirect || '/');
const urlParams = new URL(window.location.href).searchParams;
history.push(urlParams.get('redirect') || '/');
return;
}
console.log(msg);
@ -72,18 +137,35 @@ const Login: React.FC = () => {
id: 'pages.login.failure',
defaultMessage: '登录失败,请重试!',
});
console.log(error);
message.error(defaultLoginFailureMessage);
}
};
const { status, type: loginType } = userLoginState;
return (
<div className={styles.container}>
<div className={styles.lang} data-lang>
{SelectLang && <SelectLang />}
</div>
<div className={styles.content}>
<div className={containerClassName}>
<Helmet>
<title>
{intl.formatMessage({
id: 'menu.login',
defaultMessage: '登录页',
})}
- {Settings.title}
</title>
</Helmet>
<Lang />
<div
style={{
flex: '1',
padding: '32px 0',
}}
>
<LoginForm
contentStyle={{
minWidth: 280,
maxWidth: '75vw',
}}
logo={<img alt="logo" src="/logo.svg" />}
title="Ant Design"
subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })}
@ -96,30 +178,33 @@ const Login: React.FC = () => {
id="pages.login.loginWith"
defaultMessage="其他登录方式"
/>,
<AlipayCircleOutlined key="AlipayCircleOutlined" className={styles.icon} />,
<TaobaoCircleOutlined key="TaobaoCircleOutlined" className={styles.icon} />,
<WeiboCircleOutlined key="WeiboCircleOutlined" className={styles.icon} />,
<ActionIcons key="icons" />,
]}
onFinish={async (values) => {
await handleSubmit(values as API.LoginParams);
}}
>
<Tabs activeKey={type} onChange={setType}>
<Tabs.TabPane
key="account"
tab={intl.formatMessage({
id: 'pages.login.accountLogin.tab',
defaultMessage: '账户密码登录',
})}
/>
<Tabs.TabPane
key="mobile"
tab={intl.formatMessage({
id: 'pages.login.phoneLogin.tab',
defaultMessage: '手机号登录',
})}
/>
</Tabs>
<Tabs
activeKey={type}
onChange={setType}
centered
items={[
{
key: 'account',
label: intl.formatMessage({
id: 'pages.login.accountLogin.tab',
defaultMessage: '账户密码登录',
}),
},
{
key: 'mobile',
label: intl.formatMessage({
id: 'pages.login.phoneLogin.tab',
defaultMessage: '手机号登录',
}),
},
]}
/>
{status === 'error' && loginType === 'account' && (
<LoginMessage
@ -135,7 +220,7 @@ const Login: React.FC = () => {
name="username"
fieldProps={{
size: 'large',
prefix: <UserOutlined className={styles.prefixIcon} />,
prefix: <UserOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder',
@ -157,7 +242,7 @@ const Login: React.FC = () => {
name="password"
fieldProps={{
size: 'large',
prefix: <LockOutlined className={styles.prefixIcon} />,
prefix: <LockOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
@ -184,7 +269,7 @@ const Login: React.FC = () => {
<ProFormText
fieldProps={{
size: 'large',
prefix: <MobileOutlined className={styles.prefixIcon} />,
prefix: <MobileOutlined />,
}}
name="mobile"
placeholder={intl.formatMessage({
@ -215,7 +300,7 @@ const Login: React.FC = () => {
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <LockOutlined className={styles.prefixIcon} />,
prefix: <LockOutlined />,
}}
captchaProps={{
size: 'large',
@ -252,7 +337,7 @@ const Login: React.FC = () => {
const result = await getFakeCaptcha({
phone,
});
if (result === false) {
if (!result) {
return;
}
message.success('获取验证码成功!验证码为:1234');

96
src/pages/User/Login/login.test.tsx

@ -0,0 +1,96 @@
import { render, fireEvent, act } from '@testing-library/react';
import React from 'react';
import { TestBrowser } from '@@/testBrowser';
// @ts-ignore
import { startMock } from '@@/requestRecordMock';
const waitTime = (time: number = 100) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, time);
});
};
let server: {
close: () => void;
};
describe('Login Page', () => {
beforeAll(async () => {
server = await startMock({
port: 8000,
scene: 'login',
});
});
afterAll(() => {
server?.close();
});
it('should show login form', async () => {
const historyRef = React.createRef<any>();
const rootContainer = render(
<TestBrowser
historyRef={historyRef}
location={{
pathname: '/user/login',
}}
/>,
);
await rootContainer.findAllByText('Ant Design');
act(() => {
historyRef.current?.push('/user/login');
});
expect(rootContainer.baseElement?.querySelector('.ant-pro-form-login-desc')?.textContent).toBe(
'Ant Design is the most influential web design specification in Xihu district',
);
expect(rootContainer.asFragment()).toMatchSnapshot();
rootContainer.unmount();
});
it('should login success', async () => {
const historyRef = React.createRef<any>();
const rootContainer = render(
<TestBrowser
historyRef={historyRef}
location={{
pathname: '/user/login',
}}
/>,
);
await rootContainer.findAllByText('Ant Design');
const userNameInput = await rootContainer.findByPlaceholderText('Username: admin or user');
act(() => {
fireEvent.change(userNameInput, { target: { value: 'admin' } });
});
const passwordInput = await rootContainer.findByPlaceholderText('Password: ant.design');
act(() => {
fireEvent.change(passwordInput, { target: { value: 'ant.design' } });
});
await (await rootContainer.findByText('Login')).click();
// 等待接口返回结果
await waitTime(5000);
await rootContainer.findAllByText('Ant Design Pro');
expect(rootContainer.asFragment()).toMatchSnapshot();
await waitTime(2000);
rootContainer.unmount();
});
});

27
src/pages/User/register-result/style.style.ts

@ -0,0 +1,27 @@
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
registerResult: {
width: '800px',
minHeight: '400px',
margin: 'auto',
padding: '80px',
background: 'none',
':global': {
anticon: {
fontSize: '64px',
},
},
title: { marginTop: '32px', fontSize: '20px', lineHeight: '28px' },
actions: {
marginTop: '40px',
'a + a': {
marginLeft: '8px',
},
},
},
};
});
export default useStyles;

41
src/pages/User/register/style.style.ts

@ -0,0 +1,41 @@
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
main: {
width: '368px',
margin: '0 auto',
h3: { marginBottom: '20px', fontSize: '16px' },
password: {
marginBottom: '24px',
':global': {
'ant-form-item-explain': { display: 'none' },
},
},
getCaptcha: { display: 'block', width: '100%' },
submit: { width: '50%' },
login: { float: 'right', lineHeight: token.btnHeightLg },
},
'success,.warning,.error': {
transition: 'color 0.3s',
},
success: {
color: token.successColor,
},
warning: {
color: token.warningColor,
},
error: {
color: token.errorColor,
},
'progress-pass > .progress': {
':global': {
'ant-progress-bg': {
backgroundColor: token.warningColor,
},
},
},
};
});
export default useStyles;

8
src/pages/Welcome.less

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

196
src/pages/Welcome.tsx

@ -1,63 +1,161 @@
import { PageContainer } from '@ant-design/pro-components';
import { useModel } from '@umijs/max';
import { Card, theme } from 'antd';
import React from 'react';
import { PageContainer } from '@ant-design/pro-layout';
import { Card, Alert, Typography } from 'antd';
import { useIntl, FormattedMessage } from 'umi';
import styles from './Welcome.less';
const CodePreview: React.FC = ({ children }) => (
<pre className={styles.pre}>
<code>
<Typography.Text copyable>{children}</Typography.Text>
</code>
</pre>
);
/**
*
* @param param0
* @returns
*/
const InfoCard: React.FC<{
title: string;
index: number;
desc: string;
href: string;
}> = ({ title, href, index, desc }) => {
const { useToken } = theme;
const Welcome: React.FC = () => {
const intl = useIntl();
const { token } = useToken();
return (
<PageContainer>
<Card>
<Alert
message={intl.formatMessage({
id: 'pages.welcome.alertMessage',
defaultMessage: 'Faster and stronger heavy-duty components have been released.',
})}
type="success"
showIcon
banner
<div
style={{
backgroundColor: token.colorBgContainer,
boxShadow: token.boxShadow,
borderRadius: '8px',
fontSize: '14px',
color: token.colorTextSecondary,
lineHeight: '22px',
padding: '16px 19px',
minWidth: '220px',
flex: 1,
}}
>
<div
style={{
display: 'flex',
gap: '4px',
alignItems: 'center',
}}
>
<div
style={{
margin: -12,
marginBottom: 24,
width: 48,
height: 48,
lineHeight: '22px',
backgroundSize: '100%',
textAlign: 'center',
padding: '8px 16px 16px 12px',
color: '#FFF',
fontWeight: 'bold',
backgroundImage:
"url('https://gw.alipayobjects.com/zos/bmw-prod/daaf8d50-8e6d-4251-905d-676a24ddfa12.svg')",
}}
/>
<Typography.Text strong>
<FormattedMessage id="pages.welcome.advancedComponent" defaultMessage="Advanced Form" />{' '}
<a
href="https://procomponents.ant.design/components/table"
rel="noopener noreferrer"
target="__blank"
>
<FormattedMessage id="pages.welcome.link" defaultMessage="Welcome" />
</a>
</Typography.Text>
<CodePreview>yarn add @ant-design/pro-table</CodePreview>
<Typography.Text
strong
>
{index}
</div>
<div
style={{
marginBottom: 12,
fontSize: '16px',
color: token.colorText,
paddingBottom: 8,
}}
>
<FormattedMessage id="pages.welcome.advancedLayout" defaultMessage="Advanced layout" />{' '}
<a
href="https://procomponents.ant.design/components/layout"
rel="noopener noreferrer"
target="__blank"
{title}
</div>
</div>
<div
style={{
fontSize: '14px',
color: token.colorTextSecondary,
textAlign: 'justify',
lineHeight: '22px',
marginBottom: 8,
}}
>
{desc}
</div>
<a href={href} target="_blank" rel="noreferrer">
{'>'}
</a>
</div>
);
};
const Welcome: React.FC = () => {
const { token } = theme.useToken();
const { initialState } = useModel('@@initialState');
return (
<PageContainer>
<Card
style={{
borderRadius: 8,
}}
bodyStyle={{
backgroundImage:
initialState?.settings?.navTheme === 'realDark'
? 'background-image: linear-gradient(75deg, #1A1B1F 0%, #191C1F 100%)'
: 'background-image: linear-gradient(75deg, #FBFDFF 0%, #F5F7FF 100%)',
}}
>
<div
style={{
backgroundPosition: '100% -30%',
backgroundRepeat: 'no-repeat',
backgroundSize: '274px auto',
backgroundImage:
"url('https://gw.alipayobjects.com/mdn/rms_a9745b/afts/img/A*BuFmQqsB2iAAAAAAAAAAAAAAARQnAQ')",
}}
>
<div
style={{
fontSize: '20px',
color: token.colorTextHeading,
}}
>
使 Ant Design Pro
</div>
<p
style={{
fontSize: '14px',
color: token.colorTextSecondary,
lineHeight: '22px',
marginTop: 16,
marginBottom: 32,
width: '65%',
}}
>
Ant Design Pro umiAnt Design ProComponents
//
</p>
<div
style={{
display: 'flex',
flexWrap: 'wrap',
gap: 16,
}}
>
<FormattedMessage id="pages.welcome.link" defaultMessage="Welcome" />
</a>
</Typography.Text>
<CodePreview>yarn add @ant-design/pro-layout</CodePreview>
<InfoCard
index={1}
href="https://umijs.org/docs/introduce/introduce"
title="了解 umi"
desc="umi 是一个可扩展的企业级前端应用框架,umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。"
/>
<InfoCard
index={2}
title="了解 ant design"
href="https://ant.design"
desc="antd 是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。"
/>
<InfoCard
index={3}
title="了解 Pro Components"
href="https://procomponents.ant.design"
desc="ProComponents 是一个基于 Ant Design 做了更高抽象的模板组件,以 一个组件就是一个页面为开发理念,为中后台开发带来更好的体验。"
/>
</div>
</div>
</Card>
</PageContainer>
);

2
src/pages/account/center/Center.less

@ -1,4 +1,4 @@
@import '~antd/es/style/themes/default.less';
@import '~antd/es/style/themes/default.style.ts';
.avatarHolder {
margin-bottom: 24px;

76
src/pages/account/center/Center.style.ts

@ -0,0 +1,76 @@
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token }) => {
return {
avatarHolder: {
marginBottom: '24px',
textAlign: 'center',
'& > img': { width: '104px', height: '104px', marginBottom: '20px' },
name: {
marginBottom: '4px',
color: token.headingColor,
fontWeight: '500',
fontSize: '20px',
lineHeight: '28px',
},
},
detail: {
p: {
position: 'relative',
marginBottom: '8px',
paddingLeft: '26px',
'&:last-child': {
marginBottom: '0',
},
},
i: {
position: 'absolute',
top: '4px',
left: '0',
width: '14px',
height: '14px',
},
},
'tagsTitle,.teamTitle': {
marginBottom: '12px',
color: token.headingColor,
fontWeight: '500',
},
tags: {
':global': {
'ant-tag': {
marginBottom: '8px',
},
},
},
team: {
':global': {
'ant-avatar': {
marginRight: '12px',
},
},
a: {
display: 'block',
marginBottom: '24px',
overflow: 'hidden',
color: token.textColor,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
wordBreak: 'break-all',
transition: 'color 0.3s',
'&:hover': {
color: token.colorPrimary,
},
},
},
tabsCard: {
':global': {
'ant-card-head': {
padding: '0 16px',
},
},
},
};
});
export default useStyles;

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save