├── server ├── .yarnrc ├── pages │ ├── favicon.png │ ├── 5.chunk.css │ ├── 6.async.js │ ├── 7.async.js │ ├── 8.async.js │ ├── 9.async.js │ ├── asset-manifest.json │ ├── index.html │ ├── 1.async.js │ └── 5.async.js ├── test.js ├── .env ├── .gitattributes ├── .codeclimate.yml ├── pm2.json ├── bin │ ├── development.sh │ └── test.sh ├── .editorconfig ├── config │ ├── winston.js │ └── config.js ├── server │ ├── base │ │ ├── base.model.js │ │ └── base.route.js │ ├── upload │ │ ├── upload.route.js │ │ └── upload.controller.js │ └── helpers │ │ └── APIError.js ├── CONTRIBUTING.md ├── index.route.js ├── .travis.yml ├── util │ └── authChecker.js ├── index.js ├── .vscode │ └── launch.json ├── .istanbul.yml ├── README.md ├── Dockerfile ├── .dockerignore ├── .eslintrc ├── .gitignore ├── LICENSE ├── docker-compose.yml └── docker-compose.test.yml ├── antdProClient ├── .eslintignore ├── .env ├── src │ ├── services │ │ ├── config.js │ │ ├── error.js │ │ ├── upload.js │ │ ├── user.js │ │ └── ServiceBase.js │ ├── components │ │ ├── Charts │ │ │ ├── TimelineChart │ │ │ │ ├── index.less │ │ │ │ └── index.d.ts │ │ │ ├── bizcharts.d.ts │ │ │ ├── bizcharts.js │ │ │ ├── TagCloud │ │ │ │ ├── index.less │ │ │ │ └── index.d.ts │ │ │ ├── Field │ │ │ │ ├── index.d.ts │ │ │ │ ├── index.js │ │ │ │ └── index.less │ │ │ ├── demo │ │ │ │ ├── mini-progress.md │ │ │ │ ├── gauge.md │ │ │ │ ├── mini-pie.md │ │ │ │ ├── waterwave.md │ │ │ │ ├── bar.md │ │ │ │ ├── tag-cloud.md │ │ │ │ ├── mini-area.md │ │ │ │ ├── mini-bar.md │ │ │ │ ├── timeline-chart.md │ │ │ │ ├── pie.md │ │ │ │ └── radar.md │ │ │ ├── g2.js │ │ │ ├── WaterWave │ │ │ │ ├── index.d.ts │ │ │ │ └── index.less │ │ │ ├── Gauge │ │ │ │ └── index.d.ts │ │ │ ├── MiniProgress │ │ │ │ ├── index.d.ts │ │ │ │ ├── index.less │ │ │ │ └── index.js │ │ │ ├── MiniBar │ │ │ │ ├── index.d.ts │ │ │ │ └── index.js │ │ │ ├── index.less │ │ │ ├── Bar │ │ │ │ └── index.d.ts │ │ │ ├── Radar │ │ │ │ ├── index.d.ts │ │ │ │ └── index.less │ │ │ ├── ChartCard │ │ │ │ ├── index.d.ts │ │ │ │ └── index.less │ │ │ ├── MiniArea │ │ │ │ └── index.d.ts │ │ │ ├── Pie │ │ │ │ └── index.d.ts │ │ │ ├── index.d.ts │ │ │ ├── index.js │ │ │ └── autoHeight.js │ │ ├── Login │ │ │ ├── loginContext.js │ │ │ ├── LoginSubmit.js │ │ │ ├── index.less │ │ │ ├── LoginTab.js │ │ │ ├── index.d.ts │ │ │ ├── index.zh-CN.md │ │ │ └── map.js │ │ ├── DescriptionList │ │ │ ├── responsive.js │ │ │ ├── index.js │ │ │ ├── Description.d.ts │ │ │ ├── index.d.ts │ │ │ ├── Description.js │ │ │ ├── DescriptionList.js │ │ │ ├── demo │ │ │ │ ├── basic.md │ │ │ │ └── vertical.md │ │ │ ├── index.zh-CN.md │ │ │ ├── index.less │ │ │ └── index.en-US.md │ │ ├── Drawers │ │ │ └── ChangePassword.less │ │ ├── GlobalHeader │ │ │ ├── RightContent.js │ │ │ └── index.js │ │ ├── PriceConfiger │ │ │ └── index.less │ │ ├── PageHeaderWrapper │ │ │ ├── GridContent.less │ │ │ ├── index.less │ │ │ ├── GridContent.js │ │ │ └── index.js │ │ ├── NoticeIcon │ │ │ ├── demo │ │ │ │ └── basic.md │ │ │ ├── index.less │ │ │ ├── NoticeIconTab.d.ts │ │ │ ├── index.d.ts │ │ │ ├── index.zh-CN.md │ │ │ └── NoticeList.less │ │ ├── FooterToolbar │ │ │ ├── index.d.ts │ │ │ ├── index.zh-CN.md │ │ │ ├── index.en-US.md │ │ │ ├── index.less │ │ │ ├── demo │ │ │ │ └── basic.md │ │ │ └── index.js │ │ ├── StandardTable │ │ │ └── index.less │ │ ├── TagSelect │ │ │ ├── TagSelectOption.d.ts │ │ │ ├── index.d.ts │ │ │ ├── index.less │ │ │ ├── demo │ │ │ │ ├── simple.md │ │ │ │ ├── expandable.md │ │ │ │ └── controlled.md │ │ │ └── index.md │ │ ├── PageHeader │ │ │ ├── breadcrumb.d.ts │ │ │ ├── demo │ │ │ │ ├── simple.md │ │ │ │ └── structure.md │ │ │ ├── index.d.ts │ │ │ └── index.test.js │ │ ├── SelectLang │ │ │ ├── index.less │ │ │ └── index.js │ │ ├── Trend │ │ │ ├── index.d.ts │ │ │ ├── demo │ │ │ │ ├── basic.md │ │ │ │ └── reverse.md │ │ │ ├── index.md │ │ │ ├── index.less │ │ │ └── index.js │ │ ├── CountDown │ │ │ ├── index.d.ts │ │ │ ├── index.zh-CN.md │ │ │ ├── index.en-US.md │ │ │ └── demo │ │ │ │ └── simple.md │ │ ├── Authorized │ │ │ ├── Authorized.js │ │ │ ├── index.js │ │ │ ├── demo │ │ │ │ ├── basic.md │ │ │ │ ├── secured.md │ │ │ │ ├── AuthorizedArray.md │ │ │ │ └── AuthorizedFunction.md │ │ │ ├── AuthorizedRoute.js │ │ │ ├── renderAuthorize.js │ │ │ ├── index.d.ts │ │ │ └── PromiseRender.js │ │ ├── AvatarList │ │ │ ├── AvatarItem.d.ts │ │ │ ├── index.d.ts │ │ │ ├── demo │ │ │ │ └── simple.md │ │ │ ├── index.zh-CN.md │ │ │ ├── index.en-US.md │ │ │ ├── index.less │ │ │ └── index.js │ │ ├── _utils │ │ │ ├── pathTools.js │ │ │ └── pathTools.test.js │ │ ├── Exception │ │ │ ├── demo │ │ │ │ ├── 404.md │ │ │ │ ├── 500.md │ │ │ │ └── 403.md │ │ │ ├── index.d.ts │ │ │ ├── typeConfig.js │ │ │ ├── index.zh-CN.md │ │ │ ├── index.en-US.md │ │ │ └── index.js │ │ ├── PageLoading │ │ │ └── index.js │ │ ├── Result │ │ │ ├── index.d.ts │ │ │ ├── demo │ │ │ │ ├── structure.md │ │ │ │ └── error.md │ │ │ ├── index.md │ │ │ ├── index.js │ │ │ └── index.less │ │ ├── EditableLinkGroup │ │ │ ├── index.less │ │ │ └── index.js │ │ ├── GlobalFooter │ │ │ ├── index.md │ │ │ ├── index.d.ts │ │ │ ├── index.less │ │ │ ├── demo │ │ │ │ └── basic.md │ │ │ └── index.js │ │ ├── Ellipsis │ │ │ ├── index.zh-CN.md │ │ │ ├── index.less │ │ │ ├── index.test.js │ │ │ ├── index.d.ts │ │ │ ├── index.en-US.md │ │ │ └── demo │ │ │ │ ├── number.md │ │ │ │ └── line.md │ │ ├── NumberInfo │ │ │ ├── index.d.ts │ │ │ ├── index.zh-CN.md │ │ │ ├── demo │ │ │ │ └── basic.md │ │ │ ├── index.en-US.md │ │ │ ├── index.js │ │ │ └── index.less │ │ ├── SettingDrawer │ │ │ ├── ThemeColor.less │ │ │ ├── BlockChecbox.js │ │ │ └── index.less │ │ ├── EditableItem │ │ │ ├── index.less │ │ │ └── index.js │ │ ├── HeaderSearch │ │ │ ├── index.d.ts │ │ │ ├── index.zh-CN.md │ │ │ ├── index.less │ │ │ ├── demo │ │ │ │ └── basic.md │ │ │ └── index.en-US.md │ │ ├── ActiveChart │ │ │ └── index.less │ │ ├── ArticleListContent │ │ │ ├── index.js │ │ │ └── index.less │ │ ├── StandardFormRow │ │ │ ├── index.js │ │ │ └── index.less │ │ ├── SiderMenu │ │ │ └── index.js │ │ └── TopNavHeader │ │ │ ├── index.less │ │ │ └── index.js │ ├── layouts │ │ ├── MenuContext.js │ │ ├── Header.less │ │ ├── BlankLayout.js │ │ ├── Footer.js │ │ └── UserLayout.less │ ├── pages │ │ ├── Exception │ │ │ ├── style.less │ │ │ ├── 403.js │ │ │ ├── 404.js │ │ │ ├── 500.js │ │ │ ├── models │ │ │ │ └── error.js │ │ │ └── TriggerException.js │ │ ├── 404.js │ │ ├── Authorized.js │ │ └── document.ejs │ ├── utils │ │ ├── Authorized.js │ │ ├── Yuan.js │ │ ├── authority.test.js │ │ ├── authority.js │ │ └── utils.less │ ├── defaultSettings.js │ ├── e2e │ │ ├── home.e2e.js │ │ ├── login.e2e.js │ │ └── layout.e2e.js │ └── global.less ├── .firebaserc ├── jest.config.js ├── .prettierignore ├── public │ └── favicon.png ├── Dockerfile.dev ├── scripts │ └── generateMock.js ├── jsconfig.json ├── .prettierrc ├── functions │ ├── index.js │ └── package.json ├── .editorconfig ├── .stylelintrc.json ├── firebase.json ├── docker │ ├── docker-compose.dev.yml │ ├── docker-compose.yml │ └── nginx.conf ├── tests │ ├── fix_puppeteer.sh │ └── run-tests.js ├── .circleci │ └── config.yml ├── .gitignore ├── .dockerignore ├── Dockerfile ├── appveyor.yml ├── config │ ├── plugin.config.js │ └── router.config.js ├── .eslintrc.js └── LICENSE └── yarn.lock /server/.yarnrc: -------------------------------------------------------------------------------- 1 | save-prefix false 2 | -------------------------------------------------------------------------------- /antdProClient/.eslintignore: -------------------------------------------------------------------------------- 1 | /functions/mock 2 | -------------------------------------------------------------------------------- /antdProClient/.env: -------------------------------------------------------------------------------- 1 | PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 -------------------------------------------------------------------------------- /antdProClient/src/services/config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 3 | } -------------------------------------------------------------------------------- /antdProClient/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "antd-pro" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /antdProClient/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testURL: 'http://localhost:8000', 3 | }; 4 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/TimelineChart/index.less: -------------------------------------------------------------------------------- 1 | .timelineChart { 2 | background: #fff; 3 | } 4 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | -------------------------------------------------------------------------------- /server/pages/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MudOnTire/aliyun-oss-upload-demo/HEAD/server/pages/favicon.png -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/bizcharts.d.ts: -------------------------------------------------------------------------------- 1 | import * as BizChart from 'bizcharts'; 2 | 3 | export = BizChart; 4 | -------------------------------------------------------------------------------- /antdProClient/.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.md 2 | **/*.svg 3 | **/*.ejs 4 | **/*.html 5 | package.json 6 | .umi 7 | .umi-production 8 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/bizcharts.js: -------------------------------------------------------------------------------- 1 | import * as BizChart from 'bizcharts'; 2 | 3 | export default BizChart; 4 | -------------------------------------------------------------------------------- /antdProClient/src/layouts/MenuContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export default createContext(); 4 | -------------------------------------------------------------------------------- /antdProClient/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MudOnTire/aliyun-oss-upload-demo/HEAD/antdProClient/public/favicon.png -------------------------------------------------------------------------------- /server/test.js: -------------------------------------------------------------------------------- 1 | const moment = require('moment'); 2 | 3 | const start = 1551369600000; 4 | 5 | console.log(moment(start).add(3, 'months').valueOf()); 6 | -------------------------------------------------------------------------------- /antdProClient/src/components/Login/loginContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const LoginContext = createContext(); 4 | export default LoginContext; 5 | -------------------------------------------------------------------------------- /antdProClient/src/layouts/Header.less: -------------------------------------------------------------------------------- 1 | .fixedHeader { 2 | position: fixed; 3 | top: 0; 4 | right: 0; 5 | width: 100%; 6 | z-index: 9; 7 | transition: width 0.2s; 8 | } 9 | -------------------------------------------------------------------------------- /antdProClient/src/pages/Exception/style.less: -------------------------------------------------------------------------------- 1 | .trigger { 2 | background: 'red'; 3 | :global(.ant-btn) { 4 | margin-right: 8px; 5 | margin-bottom: 12px; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /antdProClient/src/services/error.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export default async function queryError(code) { 4 | return request(`/api/${code}`); 5 | } 6 | -------------------------------------------------------------------------------- /server/pages/5.chunk.css: -------------------------------------------------------------------------------- 1 | .antd-pro\\pages\\-exception\\style-trigger{background:"red"}.antd-pro\\pages\\-exception\\style-trigger .ant-btn{margin-right:8px;margin-bottom:12px} 2 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/TagCloud/index.less: -------------------------------------------------------------------------------- 1 | .tagCloud { 2 | overflow: hidden; 3 | canvas { 4 | transform: scale(0.25); 5 | transform-origin: 0 0; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/.env: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | PORT=5050 3 | 4 | ALIYUN_OSS_RULE_ASSUMER_ACCESS_KEY=LTAI4FsnfcmpY3DqGkgmwYH6 5 | ALIYUN_OSS_RULE_ASSUMER_ACCESS_KEY_SECRET=ubbLomzbxUhGfBEahBfd3dg8piS4v8 -------------------------------------------------------------------------------- /server/.gitattributes: -------------------------------------------------------------------------------- 1 | # Convert text file line endings to lf 2 | * text=auto 3 | *.js text 4 | # Denote all files that are truly binary and should not be modified. 5 | *.mp4 binary 6 | *.jpg binary 7 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/responsive.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 1: { xs: 24 }, 3 | 2: { xs: 24, sm: 12 }, 4 | 3: { xs: 24, sm: 12, md: 8 }, 5 | 4: { xs: 24, sm: 12, md: 6 }, 6 | }; 7 | -------------------------------------------------------------------------------- /antdProClient/src/components/Drawers/ChangePassword.less: -------------------------------------------------------------------------------- 1 | .main { 2 | padding: 10px; 3 | } 4 | 5 | .saveBtn { 6 | width: 280px; 7 | height: 36px; 8 | border-radius: 18px; 9 | font-size: 16px; 10 | } -------------------------------------------------------------------------------- /antdProClient/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | WORKDIR /usr/src/app/ 4 | 5 | COPY package.json ./ 6 | RUN npm install --silent --no-cache 7 | 8 | COPY ./ ./ 9 | 10 | 11 | CMD ["npm", "run", "start"] 12 | -------------------------------------------------------------------------------- /antdProClient/scripts/generateMock.js: -------------------------------------------------------------------------------- 1 | const generateMock = require('merge-umi-mock-data'); 2 | const path = require('path'); 3 | generateMock(path.join(__dirname, '../mock'), path.join(__dirname, '../functions/mock/index.js')); 4 | -------------------------------------------------------------------------------- /antdProClient/src/components/GlobalHeader/RightContent.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | 3 | 4 | export default class GlobalHeaderRight extends PureComponent { 5 | render() { 6 | return null; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /server/.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | eslint: 3 | enabled: true 4 | ratings: 5 | paths: 6 | - server/** 7 | - config/** 8 | - "**.js" 9 | exclude_paths: 10 | - node_modules/**/* 11 | - server/tests/** 12 | -------------------------------------------------------------------------------- /server/pm2.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": [ 3 | { 4 | "name": "aliyunb-oss-upload", 5 | "watch": true, 6 | "script": "./index.js", 7 | "instances": 2, 8 | "exec_mode": "cluster" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/index.js: -------------------------------------------------------------------------------- 1 | import DescriptionList from './DescriptionList'; 2 | import Description from './Description'; 3 | 4 | DescriptionList.Description = Description; 5 | export default DescriptionList; 6 | -------------------------------------------------------------------------------- /antdProClient/src/components/PriceConfiger/index.less: -------------------------------------------------------------------------------- 1 | .tag { 2 | font-size: 16px; 3 | } 4 | 5 | :global { 6 | .ant-row { 7 | padding: 8px 0; 8 | } 9 | .ant-input-number { 10 | width: 120px !important; 11 | } 12 | } -------------------------------------------------------------------------------- /antdProClient/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["./src/*"] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /server/bin/development.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # --build: Build images before starting containers. 4 | # --abort-on-container-exit: Stops all containers if any container is stopped 5 | docker-compose up --build --abort-on-container-exit 6 | -------------------------------------------------------------------------------- /antdProClient/src/components/PageHeaderWrapper/GridContent.less: -------------------------------------------------------------------------------- 1 | .main { 2 | width: 100%; 3 | height: 100%; 4 | min-height: 100%; 5 | transition: 0.3s; 6 | &.wide { 7 | max-width: 1200px; 8 | margin: 0 auto; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /antdProClient/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "printWidth": 100, 5 | "overrides": [ 6 | { 7 | "files": ".prettierrc", 8 | "options": { "parser": "json" } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/Description.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export default class Description extends React.Component< 4 | { 5 | term: React.ReactNode; 6 | style?: React.CSSProperties; 7 | }, 8 | any 9 | > {} 10 | -------------------------------------------------------------------------------- /antdProClient/src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Link from 'umi/link'; 3 | import Exception from '@/components/Exception'; 4 | 5 | export default () => ( 6 | 7 | ); 8 | -------------------------------------------------------------------------------- /antdProClient/src/components/NoticeIcon/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: 通知图标 4 | --- 5 | 6 | 通常用在导航工具栏上。 7 | 8 | ````jsx 9 | import NoticeIcon from 'ant-design-pro/lib/NoticeIcon'; 10 | 11 | ReactDOM.render(, mountNode); 12 | ```` 13 | -------------------------------------------------------------------------------- /antdProClient/src/components/PageHeaderWrapper/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .content { 4 | margin: 24px 24px 0; 5 | } 6 | 7 | @media screen and (max-width: @screen-sm) { 8 | .content { 9 | margin: 24px 0 0; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /server/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /server/config/winston.js: -------------------------------------------------------------------------------- 1 | const winston = require('winston'); 2 | 3 | const logger = new (winston.Logger)({ 4 | transports: [ 5 | new (winston.transports.Console)({ 6 | json: true, 7 | colorize: true 8 | }) 9 | ] 10 | }); 11 | 12 | module.exports = logger; 13 | -------------------------------------------------------------------------------- /server/server/base/base.model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const Schema = mongoose.Schema; 3 | 4 | module.exports = { 5 | fromUser: { type: Schema.Types.ObjectId, ref: 'account' }, 6 | createdTime: Date, 7 | updatedTime: Date, 8 | isDeleted: Boolean 9 | }; 10 | -------------------------------------------------------------------------------- /antdProClient/src/components/FooterToolbar/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IFooterToolbarProps { 3 | extra: React.ReactNode; 4 | style?: React.CSSProperties; 5 | } 6 | 7 | export default class FooterToolbar extends React.Component {} 8 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/Field/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IFieldProps { 3 | label: React.ReactNode; 4 | value: React.ReactNode; 5 | style?: React.CSSProperties; 6 | } 7 | 8 | export default class Field extends React.Component {} 9 | -------------------------------------------------------------------------------- /antdProClient/src/components/StandardTable/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .standardTable { 4 | :global { 5 | .ant-table-pagination { 6 | margin-top: 24px; 7 | } 8 | } 9 | 10 | .tableAlert { 11 | margin-bottom: 16px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/mini-progress.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | title: 迷你进度条 4 | --- 5 | 6 | ````jsx 7 | import { MiniProgress } from 'ant-design-pro/lib/Charts'; 8 | 9 | ReactDOM.render( 10 | 11 | , mountNode); 12 | ```` 13 | -------------------------------------------------------------------------------- /server/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Project 2 | 3 | All contributions are welcome! 4 | 5 | For contributing to this project, please: 6 | * fork the repository to your own account 7 | * clone the repository 8 | * make changes 9 | * submit a pull request with a unit test on `develop` branch 10 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/g2.js: -------------------------------------------------------------------------------- 1 | // 全局 G2 设置 2 | import { track, setTheme } from 'bizcharts'; 3 | 4 | track(false); 5 | 6 | const config = { 7 | defaultColor: '#1089ff', 8 | shape: { 9 | interval: { 10 | fillOpacity: 1, 11 | }, 12 | }, 13 | }; 14 | 15 | setTheme(config); 16 | -------------------------------------------------------------------------------- /antdProClient/src/components/TagSelect/TagSelectOption.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export interface ITagSelectOptionProps { 4 | value: string | number; 5 | style?: React.CSSProperties; 6 | } 7 | 8 | export default class TagSelectOption extends React.Component {} 9 | -------------------------------------------------------------------------------- /antdProClient/functions/index.js: -------------------------------------------------------------------------------- 1 | // [START functionsimport] 2 | const functions = require('firebase-functions'); 3 | const express = require('express'); 4 | const matchMock = require('./matchMock'); 5 | const app = express(); 6 | 7 | app.use(matchMock); 8 | 9 | exports.api = functions.https.onRequest(app); 10 | -------------------------------------------------------------------------------- /antdProClient/src/components/PageHeader/breadcrumb.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { IPageHeaderProps } from './index' 3 | 4 | export default class BreadcrumbView extends React.Component {} 5 | 6 | export function getBreadcrumb(breadcrumbNameMap: Object, url: string): Object; 7 | -------------------------------------------------------------------------------- /antdProClient/src/components/SelectLang/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .menu { 4 | :global(.anticon) { 5 | margin-right: 8px; 6 | } 7 | :global(.ant-dropdown-menu-item) { 8 | width: 160px; 9 | } 10 | } 11 | 12 | .dropDown { 13 | cursor: pointer; 14 | } 15 | -------------------------------------------------------------------------------- /antdProClient/src/layouts/BlankLayout.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | export default class BlankLayout extends Component { 4 | render() { 5 | const { children } = this.props; 6 | return ( 7 |
8 | {children} 9 |
10 | ) 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /antdProClient/src/components/Trend/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export interface ITrendProps { 4 | colorful?: boolean; 5 | flag: 'up' | 'down'; 6 | style?: React.CSSProperties; 7 | reverseColor?: boolean; 8 | } 9 | 10 | export default class Trend extends React.Component {} 11 | -------------------------------------------------------------------------------- /server/bin/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # --build: Build images before starting containers. 4 | # --abort-on-container-exit: Stops all containers if any container is stopped 5 | docker-compose -f 'docker-compose.test.yml' -p ci up --build --abort-on-container-exit 6 | exit $(docker wait ci_express-mongoose-es6-rest-api_1) 7 | -------------------------------------------------------------------------------- /antdProClient/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /antdProClient/.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard", "stylelint-config-prettier"], 3 | "rules": { 4 | "declaration-empty-line-before": null, 5 | "no-descending-specificity": null, 6 | "selector-pseudo-class-no-unknown": null, 7 | "selector-pseudo-element-colon-notation": null 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /antdProClient/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "dist", 4 | "rewrites": [ 5 | { "source": "/api/**", "function": "api" }, 6 | { 7 | "source": "**", 8 | "destination": "/index.html" 9 | } 10 | ], 11 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/Field/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import styles from './index.less'; 4 | 5 | const Field = ({ label, value, ...rest }) => ( 6 |
7 | {label} 8 | {value} 9 |
10 | ); 11 | 12 | export default Field; 13 | -------------------------------------------------------------------------------- /antdProClient/src/components/CountDown/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface ICountDownProps { 3 | format?: (time: number) => void; 4 | target: Date | number; 5 | onEnd?: () => void; 6 | style?: React.CSSProperties; 7 | } 8 | 9 | export default class CountDown extends React.Component {} 10 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/TagCloud/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface ITagCloudProps { 3 | data: Array<{ 4 | name: string; 5 | value: number; 6 | }>; 7 | height: number; 8 | style?: React.CSSProperties; 9 | } 10 | 11 | export default class TagCloud extends React.Component {} 12 | -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/Authorized.js: -------------------------------------------------------------------------------- 1 | import CheckPermissions from './CheckPermissions'; 2 | 3 | const Authorized = ({ children, authority, noMatch = null }) => { 4 | const childrenRender = typeof children === 'undefined' ? null : children; 5 | return CheckPermissions(authority, childrenRender, noMatch); 6 | }; 7 | 8 | export default Authorized; 9 | -------------------------------------------------------------------------------- /antdProClient/src/components/AvatarList/AvatarItem.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IAvatarItemProps { 3 | tips: React.ReactNode; 4 | src: string; 5 | style?: React.CSSProperties; 6 | } 7 | 8 | export default class AvatarItem extends React.Component { 9 | constructor(props: IAvatarItemProps); 10 | } 11 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/WaterWave/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IWaterWaveProps { 3 | title: React.ReactNode; 4 | color?: string; 5 | height: number; 6 | percent: number; 7 | style?: React.CSSProperties; 8 | } 9 | 10 | export default class WaterWave extends React.Component {} 11 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/gauge.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 7 3 | title: 仪表盘 4 | --- 5 | 6 | 仪表盘是一种进度展示方式,可以更直观的展示当前的进展情况,通常也可表示占比。 7 | 8 | ````jsx 9 | import { Gauge } from 'ant-design-pro/lib/Charts'; 10 | 11 | ReactDOM.render( 12 | 17 | , mountNode); 18 | ```` 19 | -------------------------------------------------------------------------------- /antdProClient/src/components/_utils/pathTools.js: -------------------------------------------------------------------------------- 1 | // /userinfo/2144/id => ['/userinfo','/useinfo/2144,'/userindo/2144/id'] 2 | // eslint-disable-next-line import/prefer-default-export 3 | export function urlToList(url) { 4 | const urllist = url.split('/').filter(i => i); 5 | return urllist.map((urlItem, index) => `/${urllist.slice(0, index + 1).join('/')}`); 6 | } 7 | -------------------------------------------------------------------------------- /server/server/upload/upload.route.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const uploadCtrl = require('./upload.controller'); 3 | 4 | const router = express.Router(); // eslint-disable-line new-cap 5 | 6 | router.route('/').post(uploadCtrl.upload); 7 | 8 | router.route('/credential').get(uploadCtrl.getCredential); 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/Gauge/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IGaugeProps { 3 | title: React.ReactNode; 4 | color?: string; 5 | height: number; 6 | bgColor?: number; 7 | percent: number; 8 | style?: React.CSSProperties; 9 | } 10 | 11 | export default class Gauge extends React.Component {} 12 | -------------------------------------------------------------------------------- /antdProClient/src/components/Exception/demo/404.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 404 5 | en-US: 404 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 404 页面。 11 | 12 | ## en-US 13 | 14 | 404 page. 15 | 16 | ````jsx 17 | import Exception from 'ant-design-pro/lib/Exception'; 18 | 19 | ReactDOM.render( 20 | 21 | , mountNode); 22 | ```` 23 | -------------------------------------------------------------------------------- /antdProClient/src/components/Exception/demo/500.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: 4 | zh-CN: 500 5 | en-US: 500 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 500 页面。 11 | 12 | ## en-US 13 | 14 | 500 page. 15 | 16 | ````jsx 17 | import Exception from 'ant-design-pro/lib/Exception'; 18 | 19 | ReactDOM.render( 20 | 21 | , mountNode); 22 | ```` 23 | -------------------------------------------------------------------------------- /antdProClient/src/components/PageLoading/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Spin } from 'antd'; 3 | 4 | // loading components from code split 5 | // https://umijs.org/plugin/umi-plugin-react.html#dynamicimport 6 | export default () => ( 7 |
8 | 9 |
10 | ); 11 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/MiniProgress/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IMiniProgressProps { 3 | target: number; 4 | color?: string; 5 | strokeWidth?: number; 6 | percent?: number; 7 | style?: React.CSSProperties; 8 | } 9 | 10 | export default class MiniProgress extends React.Component {} 11 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/mini-pie.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 6 3 | title: 迷你饼状图 4 | --- 5 | 6 | 通过简化 `Pie` 属性的设置,可以快速的实现极简的饼状图,可配合 `ChartCard` 组合展 7 | 现更多业务场景。 8 | 9 | ```jsx 10 | import { Pie } from 'ant-design-pro/lib/Charts'; 11 | 12 | ReactDOM.render( 13 | , 14 | mountNode 15 | ); 16 | ``` 17 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/MiniBar/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IMiniBarProps { 3 | color?: string; 4 | height: number; 5 | data: Array<{ 6 | x: number | string; 7 | y: number; 8 | }>; 9 | style?: React.CSSProperties; 10 | } 11 | 12 | export default class MiniBar extends React.Component {} 13 | -------------------------------------------------------------------------------- /antdProClient/src/components/Trend/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 演示 4 | --- 5 | 6 | 在数值背后添加一个小图标来标识涨跌情况。 7 | 8 | ````jsx 9 | import Trend from 'ant-design-pro/lib/Trend'; 10 | 11 | ReactDOM.render( 12 |
13 | 12% 14 | 11% 15 |
16 | , mountNode); 17 | ```` 18 | -------------------------------------------------------------------------------- /server/pages/6.async.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[6],{w2l6:function(e,t,l){"use strict";var n=l("g09b");Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var u=n(l("q1tI")),a=n(l("wY1l")),i=n(l("luV/")),d=function(){return u.default.createElement(i.default,{type:"404",style:{minHeight:500,height:"100%"},linkElement:a.default})};t.default=d}}]); -------------------------------------------------------------------------------- /antdProClient/src/components/FooterToolbar/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FooterToolbar 3 | subtitle: 底部工具栏 4 | cols: 1 5 | order: 6 6 | --- 7 | 8 | 固定在底部的工具栏。 9 | 10 | ## 何时使用 11 | 12 | 固定在内容区域的底部,不随滚动条移动,常用于长页面的数据搜集和提交工作。 13 | 14 | ## API 15 | 16 | 参数 | 说明 | 类型 | 默认值 17 | ----|------|-----|------ 18 | children | 工具栏内容,向右对齐 | ReactNode | - 19 | extra | 额外信息,向左对齐 | ReactNode | - 20 | -------------------------------------------------------------------------------- /antdProClient/docker/docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | ant-design-pro_dev: 5 | ports: 6 | - 8000:8000 7 | build: 8 | context: ../ 9 | dockerfile: Dockerfile.dev 10 | container_name: "ant-design-pro_dev" 11 | volumes: 12 | - ../src:/usr/src/app/src 13 | - ../config:/usr/src/app/config 14 | - ../mock:/usr/src/app/mock 15 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/Field/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .field { 4 | white-space: nowrap; 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | margin: 0; 8 | span { 9 | font-size: @font-size-base; 10 | line-height: 22px; 11 | } 12 | span:last-child { 13 | margin-left: 8px; 14 | color: @heading-color; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /antdProClient/src/components/Result/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IResultProps { 3 | type: 'success' | 'error'; 4 | title: React.ReactNode; 5 | description?: React.ReactNode; 6 | extra?: React.ReactNode; 7 | actions?: React.ReactNode; 8 | style?: React.CSSProperties; 9 | } 10 | 11 | export default class Result extends React.Component {} 12 | -------------------------------------------------------------------------------- /server/index.route.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const uploadRoutes = require('./server/upload/upload.route'); 3 | 4 | const router = express.Router(); // eslint-disable-line new-cap 5 | 6 | /** GET /health-check - Check service health */ 7 | router.get('/health-check', (req, res) => 8 | res.send('OK') 9 | ); 10 | 11 | router.use('/upload', uploadRoutes); 12 | 13 | module.exports = router; 14 | -------------------------------------------------------------------------------- /antdProClient/src/components/EditableLinkGroup/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .linkGroup { 4 | padding: 20px 0 8px 24px; 5 | font-size: 0; 6 | & > a { 7 | color: @text-color; 8 | display: inline-block; 9 | font-size: @font-size-base; 10 | margin-bottom: 13px; 11 | width: 25%; 12 | &:hover { 13 | color: @primary-color; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /antdProClient/src/components/Trend/demo/reverse.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 颜色反转 4 | --- 5 | 6 | 在数值背后添加一个小图标来标识涨跌情况。 7 | 8 | ````jsx 9 | import Trend from 'ant-design-pro/lib/Trend'; 10 | 11 | ReactDOM.render( 12 |
13 | 12% 14 | 11% 15 |
16 | , mountNode); 17 | ```` 18 | -------------------------------------------------------------------------------- /antdProClient/src/components/GlobalFooter/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | en-US: GlobalFooter 4 | zh-CN: GlobalFooter 5 | subtitle: 全局页脚 6 | cols: 1 7 | order: 7 8 | --- 9 | 10 | 页脚属于全局导航的一部分,作为对顶部导航的补充,通过传递数据控制展示内容。 11 | 12 | ## API 13 | 14 | 参数 | 说明 | 类型 | 默认值 15 | ----|------|-----|------ 16 | links | 链接数据 | array<{ title: ReactNode, href: string, blankTarget?: boolean }> | - 17 | copyright | 版权信息 | ReactNode | - 18 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/index.less: -------------------------------------------------------------------------------- 1 | .miniChart { 2 | position: relative; 3 | width: 100%; 4 | .chartContent { 5 | position: absolute; 6 | bottom: -28px; 7 | width: 100%; 8 | > div { 9 | margin: 0 -5px; 10 | overflow: hidden; 11 | } 12 | } 13 | .chartLoading { 14 | position: absolute; 15 | top: 16px; 16 | left: 50%; 17 | margin-left: -7px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /server/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8.10" 4 | - "9.9" 5 | services: 6 | - mongodb 7 | cache: 8 | directories: 9 | - node_modules 10 | git: 11 | depth: 3 12 | script: 13 | - yarn test:check-coverage 14 | after_script: 15 | - yarn report-coverage 16 | before_install: 17 | - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.5.1 18 | - export PATH=$HOME/.yarn/bin:$PATH 19 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/waterwave.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 8 3 | title: 水波图 4 | --- 5 | 6 | 水波图是一种比例的展示方式,可以更直观的展示关键值的占比。 7 | 8 | ````jsx 9 | import { WaterWave } from 'ant-design-pro/lib/Charts'; 10 | 11 | ReactDOM.render( 12 |
13 | 18 |
19 | , mountNode); 20 | ```` 21 | -------------------------------------------------------------------------------- /antdProClient/src/utils/Authorized.js: -------------------------------------------------------------------------------- 1 | import RenderAuthorized from '@/components/Authorized'; 2 | import { getAuthority } from './authority'; 3 | 4 | let Authorized = RenderAuthorized(getAuthority()); // eslint-disable-line 5 | 6 | // Reload the rights component 7 | const reloadAuthorized = () => { 8 | Authorized = RenderAuthorized(getAuthority()); 9 | }; 10 | 11 | export { reloadAuthorized }; 12 | export default Authorized; 13 | -------------------------------------------------------------------------------- /antdProClient/src/components/GlobalFooter/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IGlobalFooterProps { 3 | links?: Array<{ 4 | key?: string; 5 | title: React.ReactNode; 6 | href: string; 7 | blankTarget?: boolean; 8 | }>; 9 | copyright?: React.ReactNode; 10 | style?: React.CSSProperties; 11 | } 12 | 13 | export default class GlobalFooter extends React.Component {} 14 | -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/index.js: -------------------------------------------------------------------------------- 1 | import Authorized from './Authorized'; 2 | import AuthorizedRoute from './AuthorizedRoute'; 3 | import Secured from './Secured'; 4 | import check from './CheckPermissions'; 5 | import renderAuthorize from './renderAuthorize'; 6 | 7 | Authorized.Secured = Secured; 8 | Authorized.AuthorizedRoute = AuthorizedRoute; 9 | Authorized.check = check; 10 | 11 | export default renderAuthorize(Authorized); 12 | -------------------------------------------------------------------------------- /antdProClient/src/components/CountDown/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CountDown 3 | subtitle: 倒计时 4 | cols: 1 5 | order: 3 6 | --- 7 | 8 | 倒计时组件。 9 | 10 | ## API 11 | 12 | | 参数 | 说明 | 类型 | 默认值 | 13 | |----------|------------------------------------------|-------------|-------| 14 | | format | 时间格式化显示 | Function(time) | | 15 | | target | 目标时间 | Date | - | 16 | | onEnd | 倒计时结束回调 | funtion | -| 17 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/Bar/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IBarProps { 3 | title: React.ReactNode; 4 | color?: string; 5 | padding?: [number, number, number, number]; 6 | height: number; 7 | data: Array<{ 8 | x: string; 9 | y: number; 10 | }>; 11 | autoLabel?: boolean; 12 | style?: React.CSSProperties; 13 | } 14 | 15 | export default class Bar extends React.Component {} 16 | -------------------------------------------------------------------------------- /antdProClient/src/components/CountDown/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CountDown 3 | cols: 1 4 | order: 3 5 | --- 6 | 7 | Simple CountDown Component. 8 | 9 | ## API 10 | 11 | | Property | Description | Type | Default | 12 | |----------|------------------------------------------|-------------|-------| 13 | | format | Formatter of time | Function(time) | | 14 | | target | Target time | Date | - | 15 | | onEnd | Countdown to the end callback | funtion | -| 16 | -------------------------------------------------------------------------------- /antdProClient/src/components/Ellipsis/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ellipsis 3 | subtitle: 文本自动省略号 4 | cols: 1 5 | order: 10 6 | --- 7 | 8 | 文本过长自动处理省略号,支持按照文本长度和最大行数两种方式截取。 9 | 10 | ## API 11 | 12 | 参数 | 说明 | 类型 | 默认值 13 | ----|------|-----|------ 14 | tooltip | 移动到文本展示完整内容的提示 | boolean | - 15 | length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | - 16 | lines | 在按照行数截取下最大的行数,超过则截取省略 | number | `1` 17 | fullWidthRecognition | 是否将全角字符的长度视为2来计算字符串长度 | boolean | - 18 | -------------------------------------------------------------------------------- /antdProClient/src/services/upload.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | import { stringify } from 'qs'; 3 | import ServiceBase from './ServiceBase'; 4 | 5 | class UploadService extends ServiceBase { 6 | constructor(...props) { 7 | super(...props); 8 | } 9 | 10 | getCredential = () => { 11 | return request(`${this.urlBase}/credential`); 12 | } 13 | } 14 | 15 | const uploadService = new UploadService('upload'); 16 | 17 | export { uploadService }; -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/Radar/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IRadarProps { 3 | title?: React.ReactNode; 4 | height: number; 5 | padding?: [number, number, number, number]; 6 | hasLegend?: boolean; 7 | data: Array<{ 8 | name: string; 9 | label: string; 10 | value: string; 11 | }>; 12 | style?: React.CSSProperties; 13 | } 14 | 15 | export default class Radar extends React.Component {} 16 | -------------------------------------------------------------------------------- /antdProClient/src/components/CountDown/demo/simple.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 基本 5 | en-US: Basic 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 简单的倒计时组件使用。 11 | 12 | ## en-US 13 | 14 | The simplest usage. 15 | 16 | ````jsx 17 | import CountDown from 'ant-design-pro/lib/CountDown'; 18 | 19 | const targetTime = new Date().getTime() + 3900000; 20 | 21 | ReactDOM.render( 22 | 23 | , mountNode); 24 | ```` 25 | -------------------------------------------------------------------------------- /antdProClient/src/components/NumberInfo/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface INumberInfoProps { 3 | title?: React.ReactNode | string; 4 | subTitle?: React.ReactNode | string; 5 | total?: React.ReactNode | string; 6 | status?: 'up' | 'down'; 7 | theme?: string; 8 | gap?: number; 9 | subTotal?: number; 10 | style?: React.CSSProperties; 11 | } 12 | 13 | export default class NumberInfo extends React.Component {} 14 | -------------------------------------------------------------------------------- /antdProClient/src/defaultSettings.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | navTheme: 'dark', // theme for nav menu 3 | primaryColor: '#1890FF', // primary color of ant design 4 | layout: 'sidemenu', // nav menu position: sidemenu or topmenu 5 | contentWidth: 'Fluid', // layout of content: Fluid or Fixed, only works when layout is topmenu 6 | fixedHeader: false, // sticky header 7 | autoHideHeader: false, // auto hide header 8 | fixSiderbar: false, // sticky siderbar 9 | }; 10 | -------------------------------------------------------------------------------- /server/pages/7.async.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[7],{wOmh:function(e,t,a){"use strict";var n=a("g09b");Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var d=n(a("q1tI")),i=a("LLXN"),o=n(a("wY1l")),p=n(a("luV/")),c=function(){return d.default.createElement(p.default,{type:"403",desc:(0,i.formatMessage)({id:"app.exception.description.403"}),linkElement:o.default,backText:(0,i.formatMessage)({id:"app.exception.back"})})},u=c;t.default=u}}]); -------------------------------------------------------------------------------- /server/pages/8.async.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[8],{a7IW:function(e,t,a){"use strict";var n=a("g09b");Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var d=n(a("q1tI")),i=a("LLXN"),o=n(a("wY1l")),p=n(a("luV/")),c=function(){return d.default.createElement(p.default,{type:"404",desc:(0,i.formatMessage)({id:"app.exception.description.404"}),linkElement:o.default,backText:(0,i.formatMessage)({id:"app.exception.back"})})},u=c;t.default=u}}]); -------------------------------------------------------------------------------- /server/pages/9.async.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[9],{rywk:function(e,t,a){"use strict";var n=a("g09b");Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var d=n(a("q1tI")),i=a("LLXN"),o=n(a("wY1l")),p=n(a("luV/")),c=function(){return d.default.createElement(p.default,{type:"500",desc:(0,i.formatMessage)({id:"app.exception.description.500"}),linkElement:o.default,backText:(0,i.formatMessage)({id:"app.exception.back"})})},u=c;t.default=u}}]); -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/TimelineChart/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface ITimelineChartProps { 3 | data: Array<{ 4 | x: number; 5 | y1: number; 6 | y2?: number; 7 | }>; 8 | titleMap: { y1: string; y2?: string }; 9 | padding?: [number, number, number, number]; 10 | height?: number; 11 | style?: React.CSSProperties; 12 | } 13 | 14 | export default class TimelineChart extends React.Component {} 15 | -------------------------------------------------------------------------------- /antdProClient/src/pages/Exception/403.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { formatMessage } from 'umi/locale'; 3 | import Link from 'umi/link'; 4 | import Exception from '@/components/Exception'; 5 | 6 | const Exception403 = () => ( 7 | 13 | ); 14 | 15 | export default Exception403; 16 | -------------------------------------------------------------------------------- /antdProClient/src/pages/Exception/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { formatMessage } from 'umi/locale'; 3 | import Link from 'umi/link'; 4 | import Exception from '@/components/Exception'; 5 | 6 | const Exception404 = () => ( 7 | 13 | ); 14 | 15 | export default Exception404; 16 | -------------------------------------------------------------------------------- /antdProClient/src/pages/Exception/500.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { formatMessage } from 'umi/locale'; 3 | import Link from 'umi/link'; 4 | import Exception from '@/components/Exception'; 5 | 6 | const Exception500 = () => ( 7 | 13 | ); 14 | 15 | export default Exception500; 16 | -------------------------------------------------------------------------------- /antdProClient/src/components/AvatarList/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import AvatarItem from './AvatarItem'; 3 | 4 | export interface IAvatarListProps { 5 | size?: 'large' | 'small' | 'mini' | 'default'; 6 | style?: React.CSSProperties; 7 | children: React.ReactElement | Array>; 8 | } 9 | 10 | export default class AvatarList extends React.Component { 11 | public static Item: typeof AvatarItem; 12 | } 13 | -------------------------------------------------------------------------------- /antdProClient/src/pages/Authorized.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import RenderAuthorized from '@/components/Authorized'; 3 | import { getAuthority } from '@/utils/authority'; 4 | import Redirect from 'umi/redirect'; 5 | 6 | const Authority = getAuthority(); 7 | const Authorized = RenderAuthorized(Authority); 8 | 9 | export default ({ children }) => ( 10 | }> 11 | {children} 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /antdProClient/src/components/Ellipsis/index.less: -------------------------------------------------------------------------------- 1 | .ellipsis { 2 | overflow: hidden; 3 | display: inline-block; 4 | word-break: break-all; 5 | width: 100%; 6 | } 7 | 8 | .lines { 9 | position: relative; 10 | .shadow { 11 | display: block; 12 | position: absolute; 13 | color: transparent; 14 | opacity: 0; 15 | z-index: -999; 16 | } 17 | } 18 | 19 | .lineClamp { 20 | position: relative; 21 | overflow: hidden; 22 | text-overflow: ellipsis; 23 | display: -webkit-box; 24 | } 25 | -------------------------------------------------------------------------------- /antdProClient/src/components/Ellipsis/index.test.js: -------------------------------------------------------------------------------- 1 | import { getStrFullLength, cutStrByFullLength } from './index'; 2 | 3 | describe('test calculateShowLength', () => { 4 | it('get full length', () => { 5 | expect(getStrFullLength('一二,a,')).toEqual(8); 6 | }); 7 | it('cut str by full length', () => { 8 | expect(cutStrByFullLength('一二,a,', 7)).toEqual('一二,a'); 9 | }); 10 | it('cut str when length small', () => { 11 | expect(cutStrByFullLength('一22三', 5)).toEqual('一22'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /antdProClient/src/components/Ellipsis/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IEllipsisProps { 3 | tooltip?: boolean; 4 | length?: number; 5 | lines?: number; 6 | style?: React.CSSProperties; 7 | className?: string; 8 | fullWidthRecognition?: boolean; 9 | } 10 | 11 | export function getStrFullLength(str: string): number; 12 | export function cutStrByFullLength(str: string, maxLength: number): number; 13 | 14 | export default class Ellipsis extends React.Component {} 15 | -------------------------------------------------------------------------------- /antdProClient/src/components/Exception/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IExceptionProps { 3 | type?: '403' | '404' | '500'; 4 | title?: React.ReactNode; 5 | desc?: React.ReactNode; 6 | img?: string; 7 | actions?: React.ReactNode; 8 | linkElement?: React.ReactNode; 9 | style?: React.CSSProperties; 10 | className?: string; 11 | backText?: React.ReactNode; 12 | redirect?: string; 13 | } 14 | 15 | export default class Exception extends React.Component {} 16 | -------------------------------------------------------------------------------- /antdProClient/src/components/NumberInfo/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: NumberInfo 3 | subtitle: 数据文本 4 | cols: 1 5 | order: 10 6 | --- 7 | 8 | 常用在数据卡片中,用于突出展示某个业务数据。 9 | 10 | ## API 11 | 12 | 参数 | 说明 | 类型 | 默认值 13 | ----|------|-----|------ 14 | title | 标题 | ReactNode\|string | - 15 | subTitle | 子标题 | ReactNode\|string | - 16 | total | 总量 | ReactNode\|string | - 17 | subTotal | 子总量 | ReactNode\|string | - 18 | status | 增加状态 | 'up \| down' | - 19 | theme | 状态样式 | string | 'light' 20 | gap | 设置数字和描述之间的间距(像素)| number | 8 21 | -------------------------------------------------------------------------------- /antdProClient/src/components/SettingDrawer/ThemeColor.less: -------------------------------------------------------------------------------- 1 | .themeColor { 2 | overflow: hidden; 3 | margin-top: 24px; 4 | .title { 5 | font-size: 14px; 6 | color: rgba(0, 0, 0, 0.65); 7 | line-height: 22px; 8 | margin-bottom: 12px; 9 | } 10 | .colorBlock { 11 | width: 20px; 12 | height: 20px; 13 | border-radius: 2px; 14 | float: left; 15 | cursor: pointer; 16 | margin-right: 8px; 17 | text-align: center; 18 | color: #fff; 19 | font-weight: bold; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /antdProClient/src/pages/document.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 阿里云OSS 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /antdProClient/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | ant-design-pro_build: 5 | build: ../ 6 | container_name: "ant-design-pro_build" 7 | volumes: 8 | - dist:/usr/src/app/dist 9 | 10 | ant-design-pro_web: 11 | image: nginx 12 | ports: 13 | - 80:80 14 | container_name: "ant-design-pro_web" 15 | restart: unless-stopped 16 | volumes: 17 | - dist:/usr/share/nginx/html:ro 18 | - ./nginx.conf:/etc/nginx/conf.d/default.conf 19 | 20 | volumes: 21 | dist: 22 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Description from './Description'; 3 | 4 | export interface IDescriptionListProps { 5 | layout?: 'horizontal' | 'vertical'; 6 | col?: number; 7 | title: React.ReactNode; 8 | gutter?: number; 9 | size?: 'large' | 'small'; 10 | style?: React.CSSProperties; 11 | } 12 | 13 | export default class DescriptionList extends React.Component { 14 | public static Description: typeof Description; 15 | } 16 | -------------------------------------------------------------------------------- /server/util/authChecker.js: -------------------------------------------------------------------------------- 1 | const whiteList = []; 2 | 3 | function authChecker(req, res, next) { 4 | const inWhiteList = whiteList.some(url => req.baseUrl === url); 5 | if (inWhiteList) { 6 | next(); 7 | return; 8 | } 9 | // next(); 10 | if (!req.user) { 11 | if (req.headers['x-request-userid'] && req.headers['x-request-organizationid'] && req.method === 'GET') { 12 | next(); 13 | } else { 14 | res.sendStatus(401); 15 | } 16 | } else { 17 | next(); 18 | } 19 | }; 20 | 21 | module.exports = authChecker; -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | // config should be imported before importing any other file 2 | const config = require('./config/config'); 3 | const app = require('./config/express'); 4 | 5 | // module.parent check is required to support mocha watch 6 | // src: https://github.com/mochajs/mocha/issues/1912 7 | if (!module.parent) { 8 | // listen on port config.port 9 | app.listen(config.port, () => { 10 | console.info(`server started on port ${config.port} (${config.env})`); // eslint-disable-line no-console 11 | }); 12 | } 13 | 14 | module.exports = app; 15 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/ChartCard/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { CardProps } from 'antd/lib/card'; 3 | 4 | export interface IChartCardProps extends CardProps { 5 | title: React.ReactNode; 6 | action?: React.ReactNode; 7 | total?: React.ReactNode | number | (() => React.ReactNode | number); 8 | footer?: React.ReactNode; 9 | contentHeight?: number; 10 | avatar?: React.ReactNode; 11 | style?: React.CSSProperties; 12 | } 13 | 14 | export default class ChartCard extends React.Component {} 15 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/bar.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 4 3 | title: 柱状图 4 | --- 5 | 6 | 通过设置 `x`,`y` 属性,可以快速的构建出一个漂亮的柱状图,各种纬度的关系则是通过自定义的数据展现。 7 | 8 | ````jsx 9 | import { Bar } from 'ant-design-pro/lib/Charts'; 10 | 11 | const salesData = []; 12 | for (let i = 0; i < 12; i += 1) { 13 | salesData.push({ 14 | x: `${i + 1}月`, 15 | y: Math.floor(Math.random() * 1000) + 200, 16 | }); 17 | } 18 | 19 | ReactDOM.render( 20 | 25 | , mountNode); 26 | ```` 27 | -------------------------------------------------------------------------------- /antdProClient/src/components/Login/LoginSubmit.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { Button, Form } from 'antd'; 4 | import styles from './index.less'; 5 | 6 | const FormItem = Form.Item; 7 | 8 | const LoginSubmit = ({ className, ...rest }) => { 9 | const clsString = classNames(styles.submit, className); 10 | return ( 11 | 12 | 23 | 24 | 25 | ); 26 | ReactDOM.render( 27 | 28 | , mountNode); 29 | ```` 30 | -------------------------------------------------------------------------------- /antdProClient/src/components/Exception/typeConfig.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | 403: { 3 | img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg', 4 | title: '403', 5 | desc: '抱歉,你无权访问该页面', 6 | }, 7 | 404: { 8 | img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg', 9 | title: '404', 10 | desc: '抱歉,你访问的页面不存在', 11 | }, 12 | 500: { 13 | img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg', 14 | title: '500', 15 | desc: '抱歉,服务器出错了', 16 | }, 17 | }; 18 | 19 | export default config; 20 | -------------------------------------------------------------------------------- /antdProClient/src/components/Trend/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | en-US: Trend 4 | zh-CN: Trend 5 | subtitle: 趋势标记 6 | cols: 1 7 | order: 14 8 | --- 9 | 10 | 趋势符号,标记上升和下降趋势。通常用绿色代表“好”,红色代表“不好”,股票涨跌场景除外。 11 | 12 | ## API 13 | 14 | ```html 15 | 50% 16 | ``` 17 | 18 | | 参数 | 说明 | 类型 | 默认值 | 19 | |----------|------------------------------------------|-------------|-------| 20 | | colorful | 是否彩色标记 | Boolean | true | 21 | | flag | 上升下降标识:`up|down` | string | - | 22 | | reverseColor | 颜色反转 | Boolean | false | 23 | -------------------------------------------------------------------------------- /antdProClient/src/components/FooterToolbar/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FooterToolbar 3 | cols: 1 4 | order: 6 5 | --- 6 | 7 | A toolbar fixed at the bottom. 8 | 9 | ## Usage 10 | 11 | It is fixed at the bottom of the content area and does not move along with the scroll bar, which is usually used for data collection and submission for long pages. 12 | 13 | ## API 14 | 15 | Property | Description | Type | Default 16 | ---------|-------------|------|-------- 17 | children | toolbar content, align to the right | ReactNode | - 18 | extra | extra information, align to the left | ReactNode | - -------------------------------------------------------------------------------- /server/server/base/base.route.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const authChecker = require('../../util/authChecker'); 3 | 4 | function baseRouter(controller) { 5 | const router = express.Router(); 6 | router.route('/') 7 | .get(controller.query) 8 | .post(authChecker, controller.create) 9 | .delete(authChecker, controller.deleteMany); 10 | 11 | router.route('/:id') 12 | .get(controller.findById) 13 | .delete(authChecker, controller.remove) 14 | .put(authChecker, controller.update); 15 | 16 | return router; 17 | } 18 | 19 | module.exports = baseRouter; 20 | -------------------------------------------------------------------------------- /antdProClient/.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/node:8.11.4 6 | steps: 7 | - checkout 8 | - run: npm install 9 | - run: npm run build 10 | test: 11 | docker: 12 | - image: circleci/node:8.11.4 13 | steps: 14 | - checkout 15 | - run: sh ./tests/fix_puppeteer.sh 16 | - run: npm install 17 | - run: 18 | command : npm run test:all 19 | no_output_timeout : 30m 20 | workflows: 21 | version: 2 22 | build_and_test: 23 | jobs: 24 | - build 25 | - test -------------------------------------------------------------------------------- /antdProClient/src/e2e/home.e2e.js: -------------------------------------------------------------------------------- 1 | import puppeteer from 'puppeteer'; 2 | 3 | describe('Homepage', () => { 4 | it('it should have logo text', async () => { 5 | const browser = await puppeteer.launch({ args: ['--no-sandbox'] }); 6 | const page = await browser.newPage(); 7 | await page.goto('http://localhost:8000', { waitUntil: 'networkidle2' }); 8 | await page.waitForSelector('#logo h1'); 9 | const text = await page.evaluate(() => document.body.innerHTML); 10 | expect(text).toContain('

阿里云OSS

'); 11 | await page.close(); 12 | browser.close(); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /antdProClient/src/components/NumberInfo/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 演示 5 | en-US: Demo 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 各种数据文案的展现方式。 11 | 12 | ## en-US 13 | 14 | Used for presenting various numerical data. 15 | 16 | ````jsx 17 | import NumberInfo from 'ant-design-pro/lib/NumberInfo'; 18 | import numeral from 'numeral'; 19 | 20 | ReactDOM.render( 21 |
22 | Visits this week} 24 | total={numeral(12321).format('0,0')} 25 | status="up" 26 | subTotal={17.1} 27 | /> 28 |
29 | , mountNode); 30 | ```` 31 | -------------------------------------------------------------------------------- /antdProClient/src/pages/Exception/models/error.js: -------------------------------------------------------------------------------- 1 | import queryError from '@/services/error'; 2 | 3 | export default { 4 | namespace: 'error', 5 | 6 | state: { 7 | error: '', 8 | isloading: false, 9 | }, 10 | 11 | effects: { 12 | *query({ payload }, { call, put }) { 13 | yield call(queryError, payload.code); 14 | yield put({ 15 | type: 'trigger', 16 | payload: payload.code, 17 | }); 18 | }, 19 | }, 20 | 21 | reducers: { 22 | trigger(state, action) { 23 | return { 24 | error: action.payload, 25 | }; 26 | }, 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /server/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "nodemon", 11 | "runtimeExecutable": "nodemon", 12 | "program": "${workspaceFolder}/index.js", 13 | "restart": true, 14 | "console": "integratedTerminal", 15 | "internalConsoleOptions": "neverOpen" 16 | } 17 | 18 | ] 19 | } -------------------------------------------------------------------------------- /antdProClient/src/components/TagSelect/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import TagSelectOption from './TagSelectOption'; 3 | 4 | export interface ITagSelectProps { 5 | onChange?: (value: string[]) => void; 6 | expandable?: boolean; 7 | value?: string[] | number[]; 8 | style?: React.CSSProperties; 9 | hideCheckAll?: boolean; 10 | } 11 | 12 | export default class TagSelect extends React.Component { 13 | public static Option: typeof TagSelectOption; 14 | private children: 15 | | React.ReactElement 16 | | Array>; 17 | } 18 | -------------------------------------------------------------------------------- /antdProClient/src/components/GlobalFooter/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .globalFooter { 4 | padding: 0 16px; 5 | margin: 48px 0 24px 0; 6 | text-align: center; 7 | 8 | .links { 9 | margin-bottom: 8px; 10 | 11 | a { 12 | color: @text-color-secondary; 13 | transition: all 0.3s; 14 | 15 | &:not(:last-child) { 16 | margin-right: 40px; 17 | } 18 | 19 | &:hover { 20 | color: @text-color; 21 | } 22 | } 23 | } 24 | 25 | .copyright { 26 | color: @text-color-secondary; 27 | font-size: @font-size-base; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /antdProClient/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | **/node_modules 5 | # roadhog-api-doc ignore 6 | /src/utils/request-temp.js 7 | _roadhog-api-doc 8 | 9 | # production 10 | /dist 11 | /.vscode 12 | 13 | # misc 14 | .DS_Store 15 | npm-debug.log* 16 | yarn-error.log 17 | 18 | /coverage 19 | .idea 20 | yarn.lock 21 | package-lock.json 22 | *bak 23 | .vscode 24 | 25 | # visual studio code 26 | .history 27 | *.log 28 | 29 | functions/mock 30 | .temp/** 31 | 32 | # umi 33 | .umi 34 | .umi-production 35 | 36 | # screenshot 37 | screenshot 38 | .firebase -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 基本使用 5 | en-US: Basic use 6 | --- 7 | 8 | Basic use 9 | 10 | ```jsx 11 | import RenderAuthorized from 'ant-design-pro/lib/Authorized'; 12 | import { Alert } from 'antd'; 13 | 14 | const Authorized = RenderAuthorized('user'); 15 | const noMatch = ; 16 | 17 | ReactDOM.render( 18 |
19 | 20 | 21 | 22 |
, 23 | mountNode, 24 | ); 25 | ``` 26 | -------------------------------------------------------------------------------- /server/.istanbul.yml: -------------------------------------------------------------------------------- 1 | verbose: false 2 | instrumentation: 3 | excludes: ['dist/**', 'coverage/**', 'index.js'] 4 | include-all-sources: true 5 | reporting: 6 | print: summary 7 | reports: 8 | - lcov 9 | dir: ./coverage 10 | watermarks: 11 | statements: [50, 80] 12 | lines: [50, 80] 13 | functions: [50, 80] 14 | branches: [50, 80] 15 | check: 16 | global: 17 | statements: 50 18 | lines: 50 19 | branches: 50 20 | functions: 50 21 | each: 22 | statements: 50 23 | lines: 50 24 | branches: 30 25 | functions: 20 26 | -------------------------------------------------------------------------------- /antdProClient/.dockerignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | **/node_modules 5 | # roadhog-api-doc ignore 6 | /src/utils/request-temp.js 7 | _roadhog-api-doc 8 | 9 | # production 10 | /dist 11 | /.vscode 12 | 13 | # misc 14 | .DS_Store 15 | npm-debug.log* 16 | yarn-error.log 17 | 18 | /coverage 19 | .idea 20 | yarn.lock 21 | package-lock.json 22 | *bak 23 | .vscode 24 | 25 | # visual studio code 26 | .history 27 | *.log 28 | 29 | functions/mock 30 | .temp/** 31 | 32 | # umi 33 | .umi 34 | .umi-production 35 | 36 | # screenshot 37 | screenshot 38 | .firebase -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/demo/secured.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | title: 4 | zh-CN: 注解基本使用 5 | en-US: Basic use secured 6 | --- 7 | 8 | secured demo used 9 | 10 | ```jsx 11 | import RenderAuthorized from 'ant-design-pro/lib/Authorized'; 12 | import { Alert } from 'antd'; 13 | 14 | const { Secured } = RenderAuthorized('user'); 15 | 16 | @Secured('admin') 17 | class TestSecuredString extends React.Component { 18 | render() { 19 | ; 20 | } 21 | } 22 | ReactDOM.render( 23 |
24 | 25 |
, 26 | mountNode, 27 | ); 28 | ``` 29 | -------------------------------------------------------------------------------- /antdProClient/src/components/PageHeader/demo/simple.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | title: Simple 4 | --- 5 | 6 | 简单的页头。 7 | 8 | ````jsx 9 | import PageHeader from 'ant-design-pro/lib/PageHeader'; 10 | 11 | const breadcrumbList = [{ 12 | title: '一级菜单', 13 | href: '/', 14 | }, { 15 | title: '二级菜单', 16 | href: '/', 17 | }, { 18 | title: '三级菜单', 19 | }]; 20 | 21 | ReactDOM.render( 22 |
23 | 24 |
25 | , mountNode); 26 | ```` 27 | 28 | 33 | -------------------------------------------------------------------------------- /antdProClient/src/components/ActiveChart/index.less: -------------------------------------------------------------------------------- 1 | .activeChart { 2 | position: relative; 3 | } 4 | .activeChartGrid { 5 | p { 6 | position: absolute; 7 | top: 80px; 8 | } 9 | p:last-child { 10 | top: 115px; 11 | } 12 | } 13 | .activeChartLegend { 14 | position: relative; 15 | font-size: 0; 16 | margin-top: 8px; 17 | height: 20px; 18 | line-height: 20px; 19 | span { 20 | display: inline-block; 21 | font-size: 12px; 22 | text-align: center; 23 | width: 33.33%; 24 | } 25 | span:first-child { 26 | text-align: left; 27 | } 28 | span:last-child { 29 | text-align: right; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/AuthorizedRoute.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, Redirect } from 'react-router-dom'; 3 | import Authorized from './Authorized'; 4 | 5 | // TODO: umi只会返回render和rest 6 | const AuthorizedRoute = ({ component: Component, render, authority, redirectPath, ...rest }) => ( 7 | } />} 10 | > 11 | (Component ? : render(props))} /> 12 | 13 | ); 14 | 15 | export default AuthorizedRoute; 16 | -------------------------------------------------------------------------------- /antdProClient/src/global.less: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | } 6 | 7 | .colorWeak { 8 | filter: invert(80%); 9 | } 10 | 11 | .ant-layout { 12 | min-height: 100vh; 13 | } 14 | 15 | canvas { 16 | display: block; 17 | } 18 | 19 | body { 20 | text-rendering: optimizeLegibility; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | } 24 | 25 | .globalSpin { 26 | width: 100%; 27 | margin: 40px 0 !important; 28 | } 29 | 30 | ul, 31 | ol { 32 | list-style: none; 33 | } 34 | 35 | .link-btn{ 36 | color: @primary-color; 37 | 38 | &:hover{ 39 | cursor: pointer; 40 | } 41 | } -------------------------------------------------------------------------------- /antdProClient/src/components/HeaderSearch/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | en-US: HeaderSearch 4 | zh-CN: HeaderSearch 5 | subtitle: 顶部搜索框 6 | cols: 1 7 | order: 8 8 | --- 9 | 10 | 通常作为全局搜索的入口,放置在导航工具条右侧。 11 | 12 | ## API 13 | 14 | 参数 | 说明 | 类型 | 默认值 15 | ----|------|-----|------ 16 | placeholder | 占位文字 | string | - 17 | dataSource | 当前提示内容列表 | string[] | - 18 | onSearch | 选择某项或按下回车时的回调 | function(value) | - 19 | onChange | 输入搜索字符的回调 | function(value) | - 20 | onPressEnter | 按下回车时的回调 | function(value) | - 21 | onVisibleChange | 显示或隐藏文本框的回调 | function(value) |- 22 | defaultOpen | 输入框首次显示是否显示 | boolean | false 23 | open | 控制输入框是否显示 | booelan |false -------------------------------------------------------------------------------- /antdProClient/src/components/PageHeaderWrapper/GridContent.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { connect } from 'dva'; 3 | import styles from './GridContent.less'; 4 | 5 | class GridContent extends PureComponent { 6 | render() { 7 | const { contentWidth, children } = this.props; 8 | let className = `${styles.main}`; 9 | if (contentWidth === 'Fixed') { 10 | className = `${styles.main} ${styles.wide}`; 11 | } 12 | return
{children}
; 13 | } 14 | } 15 | 16 | export default connect(({ setting }) => ({ 17 | contentWidth: setting.contentWidth, 18 | }))(GridContent); 19 | -------------------------------------------------------------------------------- /antdProClient/src/components/Result/demo/structure.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: Structure 4 | --- 5 | 6 | 结构包含 `处理结果`,`补充信息` 以及 `操作建议` 三个部分,其中 `处理结果` 由 `提示图标`,`标题` 和 `结果描述` 组成。 7 | 8 | ````jsx 9 | import Result from 'ant-design-pro/lib/Result'; 10 | 11 | ReactDOM.render( 12 | 标题} 15 | description={
结果描述
} 16 | extra="其他补充信息,自带灰底效果" 17 | actions={
操作建议,一般放置按钮组
} 18 | /> 19 | , mountNode); 20 | ```` 21 | -------------------------------------------------------------------------------- /antdProClient/src/components/Result/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | en-US: Result 4 | zh-CN: Result 5 | subtitle: 处理结果 6 | cols: 1 7 | order: 12 8 | --- 9 | 10 | 结果页用于对用户进行的一系列任务处理结果进行反馈。 11 | 12 | ## API 13 | 14 | | 参数 | 说明 | 类型 | 默认值 | 15 | |----------|------------------------------------------|-------------|-------| 16 | | type | 类型,不同类型自带对应的图标 | Enum {'success', 'error'} | - | 17 | | title | 标题 | ReactNode | - | 18 | | description | 结果描述 | ReactNode | - | 19 | | extra | 补充信息,有默认的灰色背景 | ReactNode | - | 20 | | actions | 操作建议,推荐放置跳转链接,按钮组等 | ReactNode | - | 21 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/MiniArea/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | // g2已经更新到3.0 4 | // 不带的写了 5 | 6 | export interface IAxis { 7 | title: any; 8 | line: any; 9 | gridAlign: any; 10 | labels: any; 11 | tickLine: any; 12 | grid: any; 13 | } 14 | 15 | export interface IMiniAreaProps { 16 | color?: string; 17 | height: number; 18 | borderColor?: string; 19 | line?: boolean; 20 | animate?: boolean; 21 | xAxis?: IAxis; 22 | yAxis?: IAxis; 23 | data: Array<{ 24 | x: number | string; 25 | y: number; 26 | }>; 27 | } 28 | 29 | export default class MiniArea extends React.Component {} 30 | -------------------------------------------------------------------------------- /antdProClient/src/components/NumberInfo/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: NumberInfo 3 | cols: 1 4 | order: 10 5 | --- 6 | 7 | Often used in data cards for highlighting the business data. 8 | 9 | ## API 10 | 11 | Property | Description | Type | Default 12 | ----|------|-----|------ 13 | title | title | ReactNode\|string | - 14 | subTitle | subtitle | ReactNode\|string | - 15 | total | total amount | ReactNode\|string | - 16 | subTotal | total amount of additional information | ReactNode\|string | - 17 | status | increase state | 'up \| down' | - 18 | theme | state style | string | 'light' 19 | gap | set the spacing (pixels) between numbers and descriptions | number | 8 20 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/mini-area.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | col: 2 4 | title: 迷你区域图 5 | --- 6 | 7 | ````jsx 8 | import { MiniArea } from 'ant-design-pro/lib/Charts'; 9 | import moment from 'moment'; 10 | 11 | const visitData = []; 12 | const beginDay = new Date().getTime(); 13 | for (let i = 0; i < 20; i += 1) { 14 | visitData.push({ 15 | x: moment(new Date(beginDay + (1000 * 60 * 60 * 24 * i))).format('YYYY-MM-DD'), 16 | y: Math.floor(Math.random() * 100) + 10, 17 | }); 18 | } 19 | 20 | ReactDOM.render( 21 | 27 | , mountNode); 28 | ```` 29 | -------------------------------------------------------------------------------- /server/pages/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "vendors.css": "/vendors.chunk.css", 3 | "vendors.js": "/vendors.async.js", 4 | "1.async.js": "/1.async.js", 5 | "umi.css": "/umi.css", 6 | "umi.js": "/umi.js", 7 | "3.chunk.css": "/3.chunk.css", 8 | "3.async.js": "/3.async.js", 9 | "4.chunk.css": "/4.chunk.css", 10 | "4.async.js": "/4.async.js", 11 | "5.chunk.css": "/5.chunk.css", 12 | "5.async.js": "/5.async.js", 13 | "6.async.js": "/6.async.js", 14 | "7.async.js": "/7.async.js", 15 | "8.async.js": "/8.async.js", 16 | "9.async.js": "/9.async.js", 17 | "color.less": "/color.less", 18 | "favicon.png": "/favicon.png", 19 | "index.html": "/index.html" 20 | } -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/demo/AuthorizedArray.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: 4 | zh-CN: 使用数组作为参数 5 | en-US: Use Array as a parameter 6 | --- 7 | 8 | Use Array as a parameter 9 | 10 | ```jsx 11 | import RenderAuthorized from 'ant-design-pro/lib/Authorized'; 12 | import { Alert } from 'antd'; 13 | 14 | const Authorized = RenderAuthorized('user'); 15 | const noMatch = ; 16 | 17 | ReactDOM.render( 18 | 19 | 20 | , 21 | mountNode, 22 | ); 23 | ``` 24 | -------------------------------------------------------------------------------- /antdProClient/src/components/FooterToolbar/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .toolbar { 4 | position: fixed; 5 | width: 100%; 6 | bottom: 0; 7 | right: 0; 8 | height: 56px; 9 | line-height: 56px; 10 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03); 11 | background: #fff; 12 | border-top: 1px solid @border-color-split; 13 | padding: 0 24px; 14 | z-index: 9; 15 | 16 | &:after { 17 | content: ''; 18 | display: block; 19 | clear: both; 20 | } 21 | 22 | .left { 23 | float: left; 24 | } 25 | 26 | .right { 27 | float: right; 28 | } 29 | 30 | button + button { 31 | margin-left: 8px; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /antdProClient/src/components/ArticleListContent/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import moment from 'moment'; 3 | import { Avatar } from 'antd'; 4 | import styles from './index.less'; 5 | 6 | const ArticleListContent = ({ data: { content, updatedAt, avatar, owner, href } }) => ( 7 |
8 |
{content}
9 |
10 | 11 | {owner} 发布在 {href} 12 | {moment(updatedAt).format('YYYY-MM-DD HH:mm')} 13 |
14 |
15 | ); 16 | 17 | export default ArticleListContent; 18 | -------------------------------------------------------------------------------- /antdProClient/src/components/AvatarList/demo/simple.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 基础样例 5 | en-US: Basic Usage 6 | --- 7 | 8 | Simplest of usage. 9 | 10 | ````jsx 11 | import AvatarList from 'ant-design-pro/lib/AvatarList'; 12 | 13 | ReactDOM.render( 14 | 15 | 16 | 17 | 18 | 19 | , mountNode); 20 | ```` 21 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/mini-bar.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | col: 2 4 | title: 迷你柱状图 5 | --- 6 | 7 | 迷你柱状图更适合展示简单的区间数据,简洁的表现方式可以很好的减少大数据量的视觉展现压力。 8 | 9 | ````jsx 10 | import { MiniBar } from 'ant-design-pro/lib/Charts'; 11 | import moment from 'moment'; 12 | 13 | const visitData = []; 14 | const beginDay = new Date().getTime(); 15 | for (let i = 0; i < 20; i += 1) { 16 | visitData.push({ 17 | x: moment(new Date(beginDay + (1000 * 60 * 60 * 24 * i))).format('YYYY-MM-DD'), 18 | y: Math.floor(Math.random() * 100) + 10, 19 | }); 20 | } 21 | 22 | ReactDOM.render( 23 | 27 | , mountNode); 28 | ```` 29 | -------------------------------------------------------------------------------- /antdProClient/src/components/NoticeIcon/NoticeIconTab.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface INoticeIconData { 3 | avatar?: string|React.ReactNode; 4 | title?: React.ReactNode; 5 | description?: React.ReactNode; 6 | datetime?: React.ReactNode; 7 | extra?: React.ReactNode; 8 | style?: React.CSSProperties; 9 | } 10 | 11 | export interface INoticeIconTabProps { 12 | list?: INoticeIconData[]; 13 | title?: string; 14 | name?: string; 15 | emptyText?: React.ReactNode; 16 | emptyImage?: string; 17 | style?: React.CSSProperties; 18 | showClear?: boolean; 19 | } 20 | 21 | export default class NoticeIconTab extends React.Component {} 22 | -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | # 上传权限配置 2 | 3 | ``` 4 | { 5 | "Version": "1", 6 | "Statement": [ 7 | { 8 | "Effect": "Allow", 9 | "Action": [ 10 | "oss:PutObject", 11 | "oss:InitiateMultipartUpload", 12 | "oss:UploadPart", 13 | "oss:UploadPartCopy", 14 | "oss:CompleteMultipartUpload", 15 | "oss:AbortMultipartUpload", 16 | "oss:ListMultipartUploads", 17 | "oss:ListParts" 18 | ], 19 | "Resource": [ 20 | "acs:oss:*:*:mudontire-test", 21 | "acs:oss:*:*:mudontire-test/*" 22 | ] 23 | } 24 | ] 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/WaterWave/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .waterWave { 4 | display: inline-block; 5 | position: relative; 6 | transform-origin: left; 7 | .text { 8 | position: absolute; 9 | left: 0; 10 | top: 32px; 11 | text-align: center; 12 | width: 100%; 13 | span { 14 | color: @text-color-secondary; 15 | font-size: 14px; 16 | line-height: 22px; 17 | } 18 | h4 { 19 | color: @heading-color; 20 | line-height: 32px; 21 | font-size: 24px; 22 | } 23 | } 24 | .waterWaveCanvasWrapper { 25 | transform: scale(0.5); 26 | transform-origin: 0 0; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /antdProClient/src/utils/Yuan.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { yuan } from '@/components/Charts'; 3 | /** 4 | * 减少使用 dangerouslySetInnerHTML 5 | */ 6 | export default class Yuan extends React.PureComponent { 7 | componentDidMount() { 8 | this.rendertoHtml(); 9 | } 10 | 11 | componentDidUpdate() { 12 | this.rendertoHtml(); 13 | } 14 | 15 | rendertoHtml = () => { 16 | const { children } = this.props; 17 | if (this.main) { 18 | this.main.innerHTML = yuan(children); 19 | } 20 | }; 21 | 22 | render() { 23 | return ( 24 | { 26 | this.main = ref; 27 | }} 28 | /> 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/Pie/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IPieProps { 3 | animate?: boolean; 4 | color?: string; 5 | colors?: string[]; 6 | height: number; 7 | hasLegend?: boolean; 8 | padding?: [number, number, number, number]; 9 | percent?: number; 10 | data?: Array<{ 11 | x: string | string; 12 | y: number; 13 | }>; 14 | total?: React.ReactNode | number | (() => React.ReactNode | number); 15 | title?: React.ReactNode; 16 | tooltip?: boolean; 17 | valueFormat?: (value: string) => string | React.ReactNode; 18 | subTitle?: React.ReactNode; 19 | } 20 | 21 | export default class Pie extends React.Component {} 22 | -------------------------------------------------------------------------------- /antdProClient/src/components/Ellipsis/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ellipsis 3 | cols: 1 4 | order: 10 5 | --- 6 | 7 | When the text is too long, the Ellipsis automatically shortens it according to its length or the maximum number of lines. 8 | 9 | ## API 10 | 11 | Property | Description | Type | Default 12 | ----|------|-----|------ 13 | tooltip | tooltip for showing the full text content when hovering over | boolean | - 14 | length | maximum number of characters in the text before being truncated | number | - 15 | lines | maximum number of rows in the text before being truncated | number | `1` 16 | fullWidthRecognition | whether consider full-width character length as 2 when calculate string length | boolean | - 17 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/Description.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Col } from 'antd'; 4 | import styles from './index.less'; 5 | import responsive from './responsive'; 6 | 7 | const Description = ({ term, column, children, ...restProps }) => ( 8 | 9 | {term &&
{term}
} 10 | {children !== null && children !== undefined &&
{children}
} 11 | 12 | ); 13 | 14 | Description.defaultProps = { 15 | term: '', 16 | }; 17 | 18 | Description.propTypes = { 19 | term: PropTypes.node, 20 | }; 21 | 22 | export default Description; 23 | -------------------------------------------------------------------------------- /antdProClient/src/utils/authority.test.js: -------------------------------------------------------------------------------- 1 | import { getAuthority } from './authority'; 2 | 3 | describe('getAuthority should be strong', () => { 4 | it('empty', () => { 5 | expect(getAuthority(null)).toEqual(['admin']); // default value 6 | }); 7 | it('string', () => { 8 | expect(getAuthority('admin')).toEqual(['admin']); 9 | }); 10 | it('array with double quotes', () => { 11 | expect(getAuthority('"admin"')).toEqual(['admin']); 12 | }); 13 | it('array with single item', () => { 14 | expect(getAuthority('["admin"]')).toEqual(['admin']); 15 | }); 16 | it('array with multiple items', () => { 17 | expect(getAuthority('["admin", "guest"]')).toEqual(['admin', 'guest']); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use latest node version 8.x 2 | FROM node:8.10.0 3 | 4 | MAINTAINER Kunal Kapadia 5 | 6 | # create app directory in container 7 | RUN mkdir -p /app 8 | 9 | # set /app directory as default working directory 10 | WORKDIR /app 11 | 12 | # only copy package.json initially so that `RUN yarn` layer is recreated only 13 | # if there are changes in package.json 14 | ADD package.json yarn.lock /app/ 15 | 16 | # --pure-lockfile: Don’t generate a yarn.lock lockfile 17 | RUN yarn --pure-lockfile 18 | 19 | # copy all file from current dir to /app in container 20 | COPY . /app/ 21 | 22 | # expose port 4040 23 | EXPOSE 4040 24 | 25 | # cmd to start service 26 | CMD [ "yarn", "start" ] 27 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/timeline-chart.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 9 3 | title: 带有时间轴的图表 4 | --- 5 | 6 | 使用 `TimelineChart` 组件可以实现带有时间轴的柱状图展现,而其中的 `x` 属性,则是时间值的指向,默认最多支持同时展现两个指标,分别是 `y1` 和 `y2`。 7 | 8 | ````jsx 9 | import { TimelineChart } from 'ant-design-pro/lib/Charts'; 10 | 11 | const chartData = []; 12 | for (let i = 0; i < 20; i += 1) { 13 | chartData.push({ 14 | x: (new Date().getTime()) + (1000 * 60 * 30 * i), 15 | y1: Math.floor(Math.random() * 100) + 1000, 16 | y2: Math.floor(Math.random() * 100) + 10, 17 | }); 18 | } 19 | 20 | ReactDOM.render( 21 | 26 | , mountNode); 27 | ```` 28 | -------------------------------------------------------------------------------- /antdProClient/src/components/AvatarList/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: AvatarList 3 | subtitle: 用户头像列表 4 | order: 1 5 | cols: 1 6 | --- 7 | 8 | 一组用户头像,常用在项目/团队成员列表。可通过设置 `size` 属性来指定头像大小。 9 | 10 | ## API 11 | 12 | ### AvatarList 13 | 14 | | 参数 | 说明 | 类型 | 默认值 | 15 | |----------|------------------------------------------|-------------|-------| 16 | | size | 头像大小 | `large`、`small` 、`mini`, `default` | `default` | 17 | 18 | ### AvatarList.Item 19 | 20 | | 参数 | 说明 | 类型 | 默认值 | 21 | |----------|------------------------------------------|-------------|-------| 22 | | tips | 头像展示文案 | ReactNode\/string | - | 23 | | src | 头像图片连接 | string | - | 24 | -------------------------------------------------------------------------------- /antdProClient/src/components/TagSelect/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .tagSelect { 4 | user-select: none; 5 | margin-left: -8px; 6 | position: relative; 7 | overflow: hidden; 8 | max-height: 32px; 9 | line-height: 32px; 10 | transition: all 0.3s; 11 | :global { 12 | .ant-tag { 13 | padding: 0 8px; 14 | margin-right: 24px; 15 | font-size: @font-size-base; 16 | } 17 | } 18 | &.expanded { 19 | transition: all 0.3s; 20 | max-height: 200px; 21 | } 22 | .trigger { 23 | position: absolute; 24 | top: 0; 25 | right: 0; 26 | i { 27 | font-size: 12px; 28 | } 29 | } 30 | &.hasExpandTag { 31 | padding-right: 50px; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /antdProClient/src/components/Trend/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .trendItem { 4 | display: inline-block; 5 | font-size: @font-size-base; 6 | line-height: 22px; 7 | 8 | .up, 9 | .down { 10 | margin-left: 4px; 11 | position: relative; 12 | top: 1px; 13 | i { 14 | font-size: 12px; 15 | transform: scale(0.83); 16 | } 17 | } 18 | .up { 19 | color: @red-6; 20 | } 21 | .down { 22 | color: @green-6; 23 | top: -1px; 24 | } 25 | 26 | &.trendItemGrey .up, 27 | &.trendItemGrey .down { 28 | color: @text-color; 29 | } 30 | 31 | &.reverseColor .up { 32 | color: @green-6; 33 | } 34 | &.reverseColor .down { 35 | color: @red-6; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /antdProClient/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | WORKDIR /usr/src/app/ 4 | 5 | COPY package.json ./ 6 | RUN npm install --silent --no-cache 7 | 8 | COPY ./ ./ 9 | 10 | RUN apt-get update 11 | RUN apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \ 12 | libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \ 13 | libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \ 14 | libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \ 15 | ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget 16 | 17 | RUN npm run test:all 18 | 19 | CMD ["npm", "run", "build"] 20 | -------------------------------------------------------------------------------- /antdProClient/src/components/Exception/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Exception 3 | subtitle: 异常 4 | cols: 1 5 | order: 5 6 | --- 7 | 8 | 异常页用于对页面特定的异常状态进行反馈。通常,它包含对错误状态的阐述,并向用户提供建议或操作,避免用户感到迷失和困惑。 9 | 10 | ## API 11 | 12 | | 参数 | 说明| 类型 | 默认值 | 13 | |-------------|------------------------------------------|-------------|-------| 14 | | backText| 默认的返回按钮文本 | ReactNode| back to home | 15 | | type| 页面类型,若配置,则自带对应类型默认的 `title`,`desc`,`img`,此默认设置可以被 `title`,`desc`,`img` 覆盖 | Enum {'403', '404', '500'} | - | 16 | | title | 标题 | ReactNode| -| 17 | | desc| 补充描述| ReactNode| -| 18 | | img | 背景图片地址 | string| -| 19 | | actions | 建议操作,配置此属性时默认的『返回首页』按钮不生效| ReactNode| -| 20 | | linkElement | 定义链接的元素 | string\|ReactElement | 'a' | 21 | | redirect | 返回按钮的跳转地址 | string | '/' 22 | -------------------------------------------------------------------------------- /server/.dockerignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /antdProClient/functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "serve": "npm run mock && firebase serve --only functions", 6 | "shell": "firebase functions:shell", 7 | "start": "npm run shell", 8 | "deploy": "firebase deploy --only functions", 9 | "logs": "firebase functions:log", 10 | "mock": "node ../scripts/generateMock.js" 11 | }, 12 | "dependencies": { 13 | "@babel/runtime": "^7.0.0", 14 | "body-parser": "^1.18.3", 15 | "express": "^4.16.3", 16 | "firebase-admin": "^5.12.1", 17 | "firebase-functions": "^2.0.5", 18 | "mockjs": "^1.0.1-beta3", 19 | "moment": "^2.22.2", 20 | "path-to-regexp": "^2.2.1" 21 | }, 22 | "private": true 23 | } 24 | -------------------------------------------------------------------------------- /antdProClient/src/components/StandardFormRow/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './index.less'; 4 | 5 | const StandardFormRow = ({ title, children, last, block, grid, ...rest }) => { 6 | const cls = classNames(styles.standardFormRow, { 7 | [styles.standardFormRowBlock]: block, 8 | [styles.standardFormRowLast]: last, 9 | [styles.standardFormRowGrid]: grid, 10 | }); 11 | 12 | return ( 13 |
14 | {title && ( 15 |
16 | {title} 17 |
18 | )} 19 |
{children}
20 |
21 | ); 22 | }; 23 | 24 | export default StandardFormRow; 25 | -------------------------------------------------------------------------------- /antdProClient/appveyor.yml: -------------------------------------------------------------------------------- 1 | # Test against the latest version of this Node.js version 2 | environment: 3 | nodejs_version: "8" 4 | 5 | # this is how to allow failing jobs in the matrix 6 | matrix: 7 | fast_finish: true # set this flag to immediately finish build once one of the jobs fails. 8 | 9 | # Install scripts. (runs after repo cloning) 10 | install: 11 | # Get the latest stable version of Node.js or io.js 12 | - ps: Install-Product node $env:nodejs_version 13 | # install modules 14 | - npm install 15 | # Output useful info for debugging. 16 | - node --version 17 | - npm --version 18 | 19 | # Post-install test scripts. 20 | test_script: 21 | - npm run lint 22 | - npm run test:all 23 | - npm run build 24 | 25 | # Don't actually build. 26 | build: off 27 | -------------------------------------------------------------------------------- /antdProClient/docker/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | # gzip config 4 | gzip on; 5 | gzip_min_length 1k; 6 | gzip_comp_level 9 7 | gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; 8 | gzip_vary on; 9 | gzip_disable "MSIE [1-6]\."; 10 | 11 | root /usr/share/nginx/html; 12 | 13 | location / { 14 | try_files $uri $uri/ /index.html; 15 | } 16 | location /api { 17 | proxy_pass https://preview.pro.ant.design; 18 | proxy_set_header X-Forwarded-Proto $scheme; 19 | proxy_set_header Host $http_host; 20 | proxy_set_header X-Real-IP $remote_addr; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/demo/AuthorizedFunction.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | title: 4 | zh-CN: 使用方法作为参数 5 | en-US: Use function as a parameter 6 | --- 7 | 8 | Use Function as a parameter 9 | 10 | ```jsx 11 | import RenderAuthorized from 'ant-design-pro/lib/Authorized'; 12 | import { Alert } from 'antd'; 13 | 14 | const Authorized = RenderAuthorized('user'); 15 | const noMatch = ; 16 | 17 | const havePermission = () => { 18 | return false; 19 | }; 20 | 21 | ReactDOM.render( 22 | 23 | 28 | , 29 | mountNode, 30 | ); 31 | ``` 32 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as numeral from 'numeral'; 2 | export { default as ChartCard } from './ChartCard'; 3 | export { default as Bar } from './Bar'; 4 | export { default as Pie } from './Pie'; 5 | export { default as Radar } from './Radar'; 6 | export { default as Gauge } from './Gauge'; 7 | export { default as MiniArea } from './MiniArea'; 8 | export { default as MiniBar } from './MiniBar'; 9 | export { default as MiniProgress } from './MiniProgress'; 10 | export { default as Field } from './Field'; 11 | export { default as WaterWave } from './WaterWave'; 12 | export { default as TagCloud } from './TagCloud'; 13 | export { default as TimelineChart } from './TimelineChart'; 14 | 15 | declare const yuan: (value: number | string) => string; 16 | 17 | export { yuan }; 18 | -------------------------------------------------------------------------------- /antdProClient/src/components/HeaderSearch/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .headerSearch { 4 | :global(.anticon-search) { 5 | cursor: pointer; 6 | font-size: 16px; 7 | } 8 | .input { 9 | transition: width 0.3s, margin-left 0.3s; 10 | width: 0; 11 | background: transparent; 12 | border-radius: 0; 13 | :global(.ant-select-selection) { 14 | background: transparent; 15 | } 16 | input { 17 | border: 0; 18 | padding-left: 0; 19 | padding-right: 0; 20 | box-shadow: none !important; 21 | } 22 | &, 23 | &:hover, 24 | &:focus { 25 | border-bottom: 1px solid @border-color-base; 26 | } 27 | &.show { 28 | width: 210px; 29 | margin-left: 8px; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /server/server/upload/upload.controller.js: -------------------------------------------------------------------------------- 1 | const OSS = require('ali-oss'); 2 | const STS = OSS.STS; 3 | 4 | const sts = new STS({ 5 | accessKeyId: process.env.ALIYUN_OSS_RULE_ASSUMER_ACCESS_KEY, 6 | accessKeySecret: process.env.ALIYUN_OSS_RULE_ASSUMER_ACCESS_KEY_SECRET 7 | }); 8 | 9 | async function getCredential(req, res, next) { 10 | try { 11 | const { credentials } = await sts.assumeRole( 12 | 'acs:ram::1582938330607257:role/uploader', // role arn 13 | null, // policy 14 | 15 * 60, // expiration 15 | 'web-client' // session name 16 | ); 17 | req.result = credentials; 18 | next(); 19 | } catch (err) { 20 | next(err); 21 | } 22 | } 23 | 24 | function upload(req, res, next) { 25 | next(); 26 | } 27 | 28 | module.exports = { getCredential, upload }; -------------------------------------------------------------------------------- /antdProClient/src/components/TagSelect/demo/simple.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 基础样例 4 | --- 5 | 6 | 结合 `Tag` 的 `TagSelect` 组件,方便的应用于筛选类目的业务场景中。 7 | 8 | ````jsx 9 | import TagSelect from 'ant-design-pro/lib/TagSelect'; 10 | 11 | function handleFormSubmit(checkedValue) { 12 | console.log(checkedValue); 13 | } 14 | 15 | ReactDOM.render( 16 | 17 | 类目一 18 | 类目二 19 | 类目三 20 | 类目四 21 | 类目五 22 | 类目六 23 | 24 | , mountNode); 25 | ```` 26 | -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/renderAuthorize.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-mutable-exports */ 2 | let CURRENT = 'NULL'; 3 | /** 4 | * use authority or getAuthority 5 | * @param {string|()=>String} currentAuthority 6 | */ 7 | const renderAuthorize = Authorized => currentAuthority => { 8 | if (currentAuthority) { 9 | if (typeof currentAuthority === 'function') { 10 | CURRENT = currentAuthority(); 11 | } 12 | if ( 13 | Object.prototype.toString.call(currentAuthority) === '[object String]' || 14 | Array.isArray(currentAuthority) 15 | ) { 16 | CURRENT = currentAuthority; 17 | } 18 | } else { 19 | CURRENT = 'NULL'; 20 | } 21 | return Authorized; 22 | }; 23 | 24 | export { CURRENT }; 25 | export default Authorized => renderAuthorize(Authorized); 26 | -------------------------------------------------------------------------------- /antdProClient/src/components/SettingDrawer/BlockChecbox.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Tooltip, Icon } from 'antd'; 3 | import style from './index.less'; 4 | 5 | const BlockChecbox = ({ value, onChange, list }) => ( 6 |
7 | {list.map(item => ( 8 | 9 |
onChange(item.key)}> 10 | {item.key} 11 |
17 | 18 |
19 |
20 |
21 | ))} 22 |
23 | ); 24 | 25 | export default BlockChecbox; 26 | -------------------------------------------------------------------------------- /server/pages/index.html: -------------------------------------------------------------------------------- 1 | 阿里云OSS 2 | 3 | 9 | 10 |
-------------------------------------------------------------------------------- /antdProClient/src/components/Charts/MiniProgress/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .miniProgress { 4 | padding: 5px 0; 5 | position: relative; 6 | width: 100%; 7 | .progressWrap { 8 | background-color: @background-color-base; 9 | position: relative; 10 | } 11 | .progress { 12 | transition: all 0.4s cubic-bezier(0.08, 0.82, 0.17, 1) 0s; 13 | border-radius: 1px 0 0 1px; 14 | background-color: @primary-color; 15 | width: 0; 16 | height: 100%; 17 | } 18 | .target { 19 | position: absolute; 20 | top: 0; 21 | bottom: 0; 22 | span { 23 | border-radius: 100px; 24 | position: absolute; 25 | top: 0; 26 | left: 0; 27 | height: 4px; 28 | width: 2px; 29 | } 30 | span:last-child { 31 | top: auto; 32 | bottom: 0; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /antdProClient/src/components/HeaderSearch/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 全局搜索 4 | --- 5 | 6 | 通常放置在导航工具条右侧。(点击搜索图标预览效果) 7 | 8 | ````jsx 9 | import HeaderSearch from 'ant-design-pro/lib/HeaderSearch'; 10 | 11 | ReactDOM.render( 12 |
22 | { 26 | console.log('input', value); // eslint-disable-line 27 | }} 28 | onPressEnter={(value) => { 29 | console.log('enter', value); // eslint-disable-line 30 | }} 31 | /> 32 |
33 | , mountNode); 34 | ```` 35 | -------------------------------------------------------------------------------- /antdProClient/src/services/user.js: -------------------------------------------------------------------------------- 1 | import request from '@/utils/request'; 2 | 3 | export async function login(params) { 4 | return request('/api/accounts/login', { 5 | method: 'POST', 6 | body: params, 7 | }); 8 | } 9 | 10 | export async function logout(params) { 11 | return request('/api/accounts/logout', { 12 | method: 'POST' 13 | }); 14 | } 15 | 16 | export async function query() { 17 | return request('/api/users'); 18 | } 19 | 20 | export async function queryCurrent() { 21 | return request('/api/accounts/current'); 22 | } 23 | 24 | export async function updateCurrent(body) { 25 | return request('/api/accounts/update', { 26 | method: "PUT", 27 | body 28 | }); 29 | } 30 | 31 | export async function changePassword(body) { 32 | return request('/api/accounts/current/password', { 33 | method: "PUT", 34 | body 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /antdProClient/src/utils/authority.js: -------------------------------------------------------------------------------- 1 | // use localStorage to store the authority info, which might be sent from server in actual project. 2 | export function getAuthority(str) { 3 | const authorityString = 4 | typeof str === 'undefined' ? localStorage.getItem('cnuip-company-patent-store-authority') : str; 5 | // authorityString could be admin, "admin", ["admin"] 6 | let authority; 7 | try { 8 | authority = JSON.parse(authorityString); 9 | } catch (e) { 10 | authority = authorityString; 11 | } 12 | if (typeof authority === 'string') { 13 | return [authority]; 14 | } 15 | return authority || ['admin']; 16 | } 17 | 18 | export function setAuthority(authority) { 19 | const proAuthority = typeof authority === 'string' ? [authority] : authority; 20 | return localStorage.setItem('cnuip-company-patent-store-authority', JSON.stringify(proAuthority)); 21 | } 22 | -------------------------------------------------------------------------------- /antdProClient/src/components/Trend/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Icon } from 'antd'; 3 | import classNames from 'classnames'; 4 | import styles from './index.less'; 5 | 6 | const Trend = ({ colorful = true, reverseColor = false, flag, children, className, ...rest }) => { 7 | const classString = classNames( 8 | styles.trendItem, 9 | { 10 | [styles.trendItemGrey]: !colorful, 11 | [styles.reverseColor]: reverseColor && colorful, 12 | }, 13 | className 14 | ); 15 | return ( 16 |
17 | {children} 18 | {flag && ( 19 | 20 | 21 | 22 | )} 23 |
24 | ); 25 | }; 26 | 27 | export default Trend; 28 | -------------------------------------------------------------------------------- /antdProClient/src/components/ArticleListContent/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .listContent { 4 | .description { 5 | line-height: 22px; 6 | max-width: 720px; 7 | } 8 | .extra { 9 | color: @text-color-secondary; 10 | margin-top: 16px; 11 | line-height: 22px; 12 | & > :global(.ant-avatar) { 13 | vertical-align: top; 14 | margin-right: 8px; 15 | width: 20px; 16 | height: 20px; 17 | position: relative; 18 | top: 1px; 19 | } 20 | & > em { 21 | color: @disabled-color; 22 | font-style: normal; 23 | margin-left: 16px; 24 | } 25 | } 26 | } 27 | 28 | @media screen and (max-width: @screen-xs) { 29 | .listContent { 30 | .extra { 31 | & > em { 32 | display: block; 33 | margin-left: 0; 34 | margin-top: 8px; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /antdProClient/src/components/PageHeader/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | export interface IPageHeaderProps { 3 | title?: React.ReactNode | string; 4 | logo?: React.ReactNode | string; 5 | action?: React.ReactNode | string; 6 | content?: React.ReactNode; 7 | extraContent?: React.ReactNode; 8 | routes?: any[]; 9 | params?: any; 10 | breadcrumbList?: Array<{ title: React.ReactNode; href?: string }>; 11 | tabList?: Array<{ key: string; tab: React.ReactNode }>; 12 | tabActiveKey?: string; 13 | tabDefaultActiveKey?: string; 14 | onTabChange?: (key: string) => void; 15 | tabBarExtraContent?: React.ReactNode; 16 | linkElement?: React.ReactNode; 17 | style?: React.CSSProperties; 18 | home?: React.ReactNode; 19 | wide?: boolean; 20 | hiddenBreadcrumb?:boolean; 21 | } 22 | 23 | export default class PageHeader extends React.Component {} 24 | -------------------------------------------------------------------------------- /antdProClient/src/components/GlobalFooter/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 演示 4 | iframe: 400 5 | --- 6 | 7 | 基本页脚。 8 | 9 | ````jsx 10 | import GlobalFooter from 'ant-design-pro/lib/GlobalFooter'; 11 | import { Icon } from 'antd'; 12 | 13 | const links = [{ 14 | key: '帮助', 15 | title: '帮助', 16 | href: '', 17 | }, { 18 | key: 'github', 19 | title: , 20 | href: 'https://github.com/ant-design/ant-design-pro', 21 | blankTarget: true, 22 | }, { 23 | key: '条款', 24 | title: '条款', 25 | href: '', 26 | blankTarget: true, 27 | }]; 28 | 29 | const copyright =
Copyright 2017 蚂蚁金服体验技术部出品
; 30 | 31 | ReactDOM.render( 32 |
33 |
34 | 35 |
36 | , mountNode); 37 | ```` 38 | -------------------------------------------------------------------------------- /antdProClient/src/components/GlobalFooter/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import styles from './index.less'; 4 | 5 | const GlobalFooter = ({ className, links, copyright }) => { 6 | const clsString = classNames(styles.globalFooter, className); 7 | return ( 8 |
9 | {links && ( 10 |
11 | {links.map(link => ( 12 | 18 | {link.title} 19 | 20 | ))} 21 |
22 | )} 23 | {copyright &&
{copyright}
} 24 |
25 | ); 26 | }; 27 | 28 | export default GlobalFooter; 29 | -------------------------------------------------------------------------------- /antdProClient/src/components/HeaderSearch/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | en-US: HeaderSearch 4 | zh-CN: HeaderSearch 5 | subtitle: Top search box 6 | cols: 1 7 | order: 8 8 | --- 9 | 10 | Usually placed as an entry to the global search, placed on the right side of the navigation toolbar. 11 | 12 | ## API 13 | 14 | 参数 | 说明 | 类型 | 默认值 15 | ----|------|-----|------ 16 | placeholder | placeholder text | string | - 17 | dataSource | current list of prompts | string[] | - 18 | onSearch | Callback when selecting an item or pressing Enter | function(value) | - 19 | onChange | Enter a callback for the search text | function(value) | - 20 | onPressEnter | Callback when pressing Enter | function(value) | - 21 | onVisibleChange | Show or hide the callback of the text box | function(value) |- 22 | defaultOpen | The input box is displayed for the first time. | boolean | false 23 | open | The input box is displayed | booelan |false -------------------------------------------------------------------------------- /server/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "indent": [ 4 | 2, 5 | 2, 6 | { 7 | "SwitchCase": 1 8 | } 9 | ], 10 | "space-before-function-paren": [ 11 | 2, 12 | { 13 | "anonymous": "always", 14 | "named": "never" 15 | } 16 | ], 17 | "no-use-before-define": [ 18 | 2, 19 | "nofunc" 20 | ], 21 | // TODO: turn on later 22 | "comma-dangle": [ 23 | 0 24 | ], 25 | "import/no-extraneous-dependencies": [ 26 | "error", 27 | { 28 | "devDependencies": true 29 | } 30 | ], 31 | "no-underscore-dangle": [ 32 | 0 33 | ] 34 | }, 35 | "env": { 36 | "node": true, 37 | "mocha": true 38 | }, 39 | "parserOptions": { 40 | "ecmaVersion": 6, 41 | "sourceType": "module" 42 | }, 43 | "extends": [ 44 | "eslint:recommended", 45 | "airbnb-base" 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /antdProClient/src/components/AvatarList/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: AvatarList 3 | order: 1 4 | cols: 1 5 | --- 6 | 7 | A list of user's avatar for project or group member list frequently. If a large or small AvatarList is desired, set the `size` property to either `large` or `small` and `mini` respectively. Omit the `size` property for a AvatarList with the default size. 8 | 9 | ## API 10 | 11 | ### AvatarList 12 | 13 | | Property | Description | Type | Default | 14 | |----------|------------------------------------------|-------------|-------| 15 | | size | size of list | `large`、`small` 、`mini`, `default` | `default` | 16 | 17 | ### AvatarList.Item 18 | 19 | | Property | Description | Type | Default | 20 | |----------|------------------------------------------|-------------|-------| 21 | | tips | title tips for avatar item | ReactNode\/string | - | 22 | | src | the address of the image for an image avatar | string | - | 23 | -------------------------------------------------------------------------------- /antdProClient/src/components/AvatarList/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .avatarList { 4 | display: inline-block; 5 | ul { 6 | display: inline-block; 7 | margin-left: 8px; 8 | font-size: 0; 9 | } 10 | } 11 | 12 | .avatarItem { 13 | display: inline-block; 14 | font-size: @font-size-base; 15 | margin-left: -8px; 16 | width: @avatar-size-base; 17 | height: @avatar-size-base; 18 | :global { 19 | .ant-avatar { 20 | border: 1px solid #fff; 21 | } 22 | } 23 | } 24 | 25 | .avatarItemLarge { 26 | width: @avatar-size-lg; 27 | height: @avatar-size-lg; 28 | } 29 | 30 | .avatarItemSmall { 31 | width: @avatar-size-sm; 32 | height: @avatar-size-sm; 33 | } 34 | 35 | .avatarItemMini { 36 | width: 20px; 37 | height: 20px; 38 | :global { 39 | .ant-avatar { 40 | width: 20px; 41 | height: 20px; 42 | line-height: 20px; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /antdProClient/src/components/Ellipsis/demo/number.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 按照字符数省略 5 | en-US: Truncate according to the number of character 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 通过设置 `length` 属性指定文本最长长度,如果超过这个长度会自动截取。 11 | 12 | ## en-US 13 | 14 | `length` attribute specifies the maximum length where the text will automatically be truncated when exceeded. 15 | 16 | ````jsx 17 | import Ellipsis from 'ant-design-pro/lib/Ellipsis'; 18 | 19 | const article = 'There were injuries alleged in three cases in 2015, and a fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.'; 20 | 21 | ReactDOM.render( 22 |
23 | {article} 24 |

Show Tooltip

25 | {article} 26 |
27 | , mountNode); 28 | ```` 29 | -------------------------------------------------------------------------------- /antdProClient/src/services/ServiceBase.js: -------------------------------------------------------------------------------- 1 | import { stringify } from 'qs'; 2 | import request from '@/utils/request'; 3 | 4 | export default class ServiceBase { 5 | constructor(resource) { 6 | this.urlBase = `/api/${resource}`; 7 | } 8 | 9 | queryItems = async (params) => { 10 | return request(`${this.urlBase}?${stringify(params)}`); 11 | } 12 | 13 | saveItem = async (params) => { 14 | if (params._id) { 15 | return request(`${this.urlBase}/${params._id}`, { 16 | method: "PUT", 17 | body: params 18 | }); 19 | } 20 | return request(this.urlBase, { 21 | method: "POST", 22 | body: params 23 | }); 24 | } 25 | 26 | getItemDetail = async (params) => { 27 | return request(`${this.urlBase}/${params._id}`); 28 | } 29 | 30 | deleteItem = async (params) => { 31 | return request(`${this.urlBase}/${params._id}`, { 32 | method: "DELETE" 33 | }); 34 | } 35 | } -------------------------------------------------------------------------------- /antdProClient/config/plugin.config.js: -------------------------------------------------------------------------------- 1 | // Change theme plugin 2 | 3 | import MergeLessPlugin from 'antd-pro-merge-less'; 4 | import AntDesignThemePlugin from 'antd-pro-theme-webpack-plugin'; 5 | import path from 'path'; 6 | 7 | export default config => { 8 | // 将所有 less 合并为一个供 themePlugin使用 9 | const outFile = path.join(__dirname, '../.temp/ant-design-pro.less'); 10 | const stylesDir = path.join(__dirname, '../src/'); 11 | 12 | config.plugin('merge-less').use(MergeLessPlugin, [ 13 | { 14 | stylesDir, 15 | outFile, 16 | }, 17 | ]); 18 | 19 | config.plugin('ant-design-theme').use(AntDesignThemePlugin, [ 20 | { 21 | antDir: path.join(__dirname, '../node_modules/antd'), 22 | stylesDir, 23 | varFile: path.join(__dirname, '../node_modules/antd/lib/style/themes/default.less'), 24 | mainLessFile: outFile, // themeVariables: ['@primary-color'], 25 | indexFileName: 'index.html', 26 | }, 27 | ]); 28 | }; 29 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/MiniProgress/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Tooltip } from 'antd'; 3 | 4 | import styles from './index.less'; 5 | 6 | const MiniProgress = ({ target, color = 'rgb(19, 194, 194)', strokeWidth, percent }) => ( 7 |
8 | 9 |
10 | 11 | 12 |
13 |
14 |
15 |
23 |
24 |
25 | ); 26 | 27 | export default MiniProgress; 28 | -------------------------------------------------------------------------------- /antdProClient/src/components/Login/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .login { 4 | :global { 5 | .ant-tabs .ant-tabs-bar { 6 | border-bottom: 0; 7 | margin-bottom: 24px; 8 | text-align: center; 9 | } 10 | 11 | .ant-form-item { 12 | margin: 0 2px 24px; 13 | } 14 | } 15 | 16 | .icon { 17 | font-size: 24px; 18 | color: rgba(0, 0, 0, 0.2); 19 | margin-left: 16px; 20 | vertical-align: middle; 21 | cursor: pointer; 22 | transition: color 0.3s; 23 | 24 | &:hover { 25 | color: @primary-color; 26 | } 27 | } 28 | 29 | .other { 30 | text-align: left; 31 | margin-top: 24px; 32 | line-height: 22px; 33 | 34 | .register { 35 | float: right; 36 | } 37 | } 38 | 39 | .prefixIcon { 40 | font-size: @font-size-base; 41 | color: @disabled-color; 42 | } 43 | 44 | .submit { 45 | width: 100%; 46 | margin-top: 24px; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /antdProClient/src/components/TagSelect/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | en-US: TagSelect 4 | zh-CN: TagSelect 5 | subtitle: 标签选择器 6 | cols: 1 7 | order: 13 8 | --- 9 | 10 | 可进行多选,带折叠收起和展开更多功能,常用于对列表进行筛选。 11 | 12 | ## API 13 | 14 | ### TagSelect 15 | 16 | | 参数 | 说明 | 类型 | 默认值 | 17 | |----------|------------------------------------------|-------------|-------| 18 | | value |选中的项 |string[] \| number[] | | 19 | | defaultValue |默认选中的项 |string[] \| number[] | | 20 | | onChange | 标签选择的回调函数 | Function(checkedTags) | | 21 | | expandable | 是否展示 `展开/收起` 按钮 | Boolean | false | 22 | | hideCheckAll | 隐藏 `全部` 按钮 | Boolean | false | 23 | 24 | ### TagSelectOption 25 | 26 | | 参数 | 说明 | 类型 | 默认值 | 27 | |----------|------------------------------------------|-------------|-------| 28 | | value | TagSelect的值 | string\| number | - | 29 | | children | tag的内容 | string \| ReactNode | - | 30 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # IDE 12 | .idea 13 | 14 | # OS generated files 15 | .DS_Store 16 | .DS_Store? 17 | ._* 18 | .Spotlight-V100 19 | ehthumbs.db 20 | Icon? 21 | Thumbs.db 22 | 23 | # Babel ES6 compiles files 24 | dist 25 | 26 | # Directory for instrumented libs generated by jscoverage/JSCover 27 | lib-cov 28 | 29 | # Coverage directory used by tools like istanbul 30 | coverage 31 | 32 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (http://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directory 42 | node_modules 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional REPL history 48 | .node_repl_history 49 | 50 | # .env 51 | # .env 52 | 53 | 54 | # upload desc 55 | uploaded 56 | 57 | # local history 58 | .history -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/pie.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 5 3 | title: 饼状图 4 | --- 5 | 6 | ```jsx 7 | import { Pie, yuan } from 'ant-design-pro/lib/Charts'; 8 | 9 | const salesPieData = [ 10 | { 11 | x: '家用电器', 12 | y: 4544, 13 | }, 14 | { 15 | x: '食用酒水', 16 | y: 3321, 17 | }, 18 | { 19 | x: '个护健康', 20 | y: 3113, 21 | }, 22 | { 23 | x: '服饰箱包', 24 | y: 2341, 25 | }, 26 | { 27 | x: '母婴产品', 28 | y: 1231, 29 | }, 30 | { 31 | x: '其他', 32 | y: 1231, 33 | }, 34 | ]; 35 | 36 | ReactDOM.render( 37 | ( 42 | now.y + pre, 0)) 45 | }} 46 | /> 47 | )} 48 | data={salesPieData} 49 | valueFormat={val => } 50 | height={294} 51 | />, 52 | mountNode, 53 | ); 54 | ``` 55 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/DescriptionList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { Row } from 'antd'; 4 | import styles from './index.less'; 5 | 6 | const DescriptionList = ({ 7 | className, 8 | title, 9 | col = 3, 10 | layout = 'horizontal', 11 | gutter = 32, 12 | children, 13 | size, 14 | ...restProps 15 | }) => { 16 | const clsString = classNames(styles.descriptionList, styles[layout], className, { 17 | [styles.small]: size === 'small', 18 | [styles.large]: size === 'large', 19 | }); 20 | const column = col > 4 ? 4 : col; 21 | return ( 22 |
23 | {title ?
{title}
: null} 24 | 25 | {React.Children.map( 26 | children, 27 | child => (child ? React.cloneElement(child, { column }) : child) 28 | )} 29 | 30 |
31 | ); 32 | }; 33 | 34 | export default DescriptionList; 35 | -------------------------------------------------------------------------------- /antdProClient/src/components/Result/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { Icon } from 'antd'; 4 | import styles from './index.less'; 5 | 6 | export default function Result({ 7 | className, 8 | type, 9 | title, 10 | description, 11 | extra, 12 | actions, 13 | ...restProps 14 | }) { 15 | const iconMap = { 16 | error: , 17 | success: , 18 | }; 19 | const clsString = classNames(styles.result, className); 20 | return ( 21 |
22 |
{iconMap[type]}
23 |
{title}
24 | {description &&
{description}
} 25 | {extra &&
{extra}
} 26 | {actions &&
{actions}
} 27 |
28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /antdProClient/src/components/Login/LoginTab.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Tabs } from 'antd'; 3 | import LoginContext from './loginContext'; 4 | 5 | const { TabPane } = Tabs; 6 | 7 | const generateId = (() => { 8 | let i = 0; 9 | return (prefix = '') => { 10 | i += 1; 11 | return `${prefix}${i}`; 12 | }; 13 | })(); 14 | 15 | class LoginTab extends Component { 16 | constructor(props) { 17 | super(props); 18 | this.uniqueId = generateId('login-tab-'); 19 | } 20 | 21 | componentDidMount() { 22 | const { tabUtil } = this.props; 23 | tabUtil.addTab(this.uniqueId); 24 | } 25 | 26 | render() { 27 | const { children } = this.props; 28 | return {children}; 29 | } 30 | } 31 | 32 | const wrapContext = props => ( 33 | 34 | {value => } 35 | 36 | ); 37 | 38 | // 标志位 用来判断是不是自定义组件 39 | wrapContext.typeName = 'LoginTab'; 40 | 41 | export default wrapContext; 42 | -------------------------------------------------------------------------------- /antdProClient/src/components/NoticeIcon/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import NoticeIconTab, { INoticeIconData } from './NoticeIconTab'; 3 | 4 | export interface INoticeIconProps { 5 | count?: number; 6 | bell?: React.ReactNode; 7 | className?: string; 8 | loading?: boolean; 9 | onClear?: (tabName: string) => void; 10 | onItemClick?: (item: INoticeIconData, tabProps: INoticeIconProps) => void; 11 | onTabChange?: (tabTile: string) => void; 12 | popupAlign?: { 13 | points?: [string, string]; 14 | offset?: [number, number]; 15 | targetOffset?: [number, number]; 16 | overflow?: any; 17 | useCssRight?: boolean; 18 | useCssBottom?: boolean; 19 | useCssTransform?: boolean; 20 | }; 21 | style?: React.CSSProperties; 22 | onPopupVisibleChange?: (visible: boolean) => void; 23 | popupVisible?: boolean; 24 | locale?: { emptyText: string; clear: string }; 25 | } 26 | 27 | export default class NoticeIcon extends React.Component { 28 | public static Tab: typeof NoticeIconTab; 29 | } 30 | -------------------------------------------------------------------------------- /antdProClient/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'babel-eslint', 3 | extends: ['airbnb', 'prettier', 'plugin:compat/recommended'], 4 | env: { 5 | browser: true, 6 | node: true, 7 | es6: true, 8 | mocha: true, 9 | jest: true, 10 | jasmine: true, 11 | }, 12 | globals: { 13 | APP_TYPE: true, 14 | }, 15 | rules: { 16 | 'react/jsx-filename-extension': [1, { extensions: ['.js'] }], 17 | 'react/jsx-wrap-multilines': 0, 18 | 'react/prop-types': 0, 19 | 'react/forbid-prop-types': 0, 20 | 'react/jsx-one-expression-per-line': 0, 21 | 'import/no-unresolved': [2, { ignore: ['^@/', '^umi/'] }], 22 | 'import/no-extraneous-dependencies': [2, { optionalDependencies: true }], 23 | 'jsx-a11y/no-noninteractive-element-interactions': 0, 24 | 'jsx-a11y/click-events-have-key-events': 0, 25 | 'jsx-a11y/no-static-element-interactions': 0, 26 | 'jsx-a11y/anchor-is-valid': 0, 27 | 'linebreak-style': 0, 28 | }, 29 | settings: { 30 | polyfills: ['fetch', 'promises', 'url'], 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /antdProClient/src/components/Exception/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Exception 3 | cols: 1 4 | order: 5 5 | --- 6 | 7 | Exceptions page is used to provide feedback on specific abnormal state. Usually, it contains an explanation of the error status, and provides users with suggestions or operations, to prevent users from feeling lost and confused. 8 | 9 | ## API 10 | 11 | Property | Description | Type | Default 12 | ---------|-------------|------|-------- 13 | | backText | default return button text | ReactNode | back to home | 14 | type | type of exception, the corresponding default `title`, `desc`, `img` will be given if set, which can be overridden by explicit setting of `title`, `desc`, `img` | Enum {'403', '404', '500'} | - 15 | title | title | ReactNode | - 16 | desc | supplementary description | ReactNode | - 17 | img | the url of background image | string | - 18 | actions | suggested operations, a default 'Home' link will show if not set | ReactNode | - 19 | linkElement | to specify the element of link | string\|ReactElement | 'a' 20 | redirect | redirect path | string | '/' -------------------------------------------------------------------------------- /server/pages/1.async.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[1],{YmWs:function(e,t,r){"use strict";var a=r("g09b");Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=a(r("d6i3")),u=a(r("k63P")),c={namespace:"error",state:{error:"",isloading:!1},effects:{query:n.default.mark(function e(t,r){var a,c,o;return n.default.wrap(function(e){while(1)switch(e.prev=e.next){case 0:return a=t.payload,c=r.call,o=r.put,e.next=4,c(u.default,a.code);case 4:return e.next=6,o({type:"trigger",payload:a.code});case 6:case"end":return e.stop()}},e)})},reducers:{trigger:function(e,t){return{error:t.payload}}}};t.default=c},k63P:function(e,t,r){"use strict";var a=r("g09b");Object.defineProperty(t,"__esModule",{value:!0}),t.default=o;var n=a(r("d6i3")),u=a(r("1l/V")),c=a(r("t3Un"));function o(e){return i.apply(this,arguments)}function i(){return i=(0,u.default)(n.default.mark(function e(t){return n.default.wrap(function(e){while(1)switch(e.prev=e.next){case 0:return e.abrupt("return",(0,c.default)("/api/".concat(t)));case 1:case"end":return e.stop()}},e)})),i.apply(this,arguments)}}}]); -------------------------------------------------------------------------------- /antdProClient/src/utils/utils.less: -------------------------------------------------------------------------------- 1 | .textOverflow() { 2 | overflow: hidden; 3 | text-overflow: ellipsis; 4 | word-break: break-all; 5 | white-space: nowrap; 6 | } 7 | 8 | .textOverflowMulti(@line: 3, @bg: #fff) { 9 | overflow: hidden; 10 | position: relative; 11 | line-height: 1.5em; 12 | max-height: @line * 1.5em; 13 | text-align: justify; 14 | margin-right: -1em; 15 | padding-right: 1em; 16 | &:before { 17 | background: @bg; 18 | content: '...'; 19 | padding: 0 1px; 20 | position: absolute; 21 | right: 14px; 22 | bottom: 0; 23 | } 24 | &:after { 25 | background: white; 26 | content: ''; 27 | margin-top: 0.2em; 28 | position: absolute; 29 | right: 14px; 30 | width: 1em; 31 | height: 1em; 32 | } 33 | } 34 | 35 | // mixins for clearfix 36 | // ------------------------ 37 | .clearfix() { 38 | zoom: 1; 39 | &:before, 40 | &:after { 41 | content: ' '; 42 | display: table; 43 | } 44 | &:after { 45 | clear: both; 46 | visibility: hidden; 47 | font-size: 0; 48 | height: 0; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /antdProClient/src/components/Login/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Button from 'antd/lib/button'; 3 | export interface LoginProps { 4 | defaultActiveKey?: string; 5 | onTabChange?: (key: string) => void; 6 | style?: React.CSSProperties; 7 | onSubmit?: (error: any, values: any) => void; 8 | } 9 | 10 | export interface TabProps { 11 | key?: string; 12 | tab?: React.ReactNode; 13 | } 14 | export class Tab extends React.Component {} 15 | 16 | export interface LoginItemProps { 17 | name?: string; 18 | rules?: any[]; 19 | style?: React.CSSProperties; 20 | onGetCaptcha?: () => void; 21 | placeholder?: string; 22 | buttonText?: React.ReactNode; 23 | } 24 | 25 | export class LoginItem extends React.Component {} 26 | 27 | export default class Login extends React.Component { 28 | static Tab: typeof Tab; 29 | static UserName: typeof LoginItem; 30 | static Password: typeof LoginItem; 31 | static Mobile: typeof LoginItem; 32 | static Captcha: typeof LoginItem; 33 | static Submit: typeof Button; 34 | } 35 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/index.js: -------------------------------------------------------------------------------- 1 | import numeral from 'numeral'; 2 | import './g2'; 3 | import ChartCard from './ChartCard'; 4 | import Bar from './Bar'; 5 | import Pie from './Pie'; 6 | import Radar from './Radar'; 7 | import Gauge from './Gauge'; 8 | import MiniArea from './MiniArea'; 9 | import MiniBar from './MiniBar'; 10 | import MiniProgress from './MiniProgress'; 11 | import Field from './Field'; 12 | import WaterWave from './WaterWave'; 13 | import TagCloud from './TagCloud'; 14 | import TimelineChart from './TimelineChart'; 15 | 16 | const yuan = val => `¥ ${numeral(val).format('0,0')}`; 17 | 18 | const Charts = { 19 | yuan, 20 | Bar, 21 | Pie, 22 | Gauge, 23 | Radar, 24 | MiniBar, 25 | MiniArea, 26 | MiniProgress, 27 | ChartCard, 28 | Field, 29 | WaterWave, 30 | TagCloud, 31 | TimelineChart, 32 | }; 33 | 34 | export { 35 | Charts as default, 36 | yuan, 37 | Bar, 38 | Pie, 39 | Gauge, 40 | Radar, 41 | MiniBar, 42 | MiniArea, 43 | MiniProgress, 44 | ChartCard, 45 | Field, 46 | WaterWave, 47 | TagCloud, 48 | TimelineChart, 49 | }; 50 | -------------------------------------------------------------------------------- /antdProClient/src/components/Result/demo/error.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | title: Failed 4 | --- 5 | 6 | 提交失败。 7 | 8 | ````jsx 9 | import Result from 'ant-design-pro/lib/Result'; 10 | import { Button, Icon } from 'antd'; 11 | 12 | const extra = ( 13 |
14 |
15 | 您提交的内容有如下错误: 16 |
17 |
18 | 您的账户已被冻结 19 | 立即解冻 20 |
21 |
22 | 您的账户还不具备申请资格 23 | 立即升级 24 |
25 |
26 | ); 27 | 28 | const actions = ; 29 | 30 | ReactDOM.render( 31 | 38 | , mountNode); 39 | ```` 40 | -------------------------------------------------------------------------------- /antdProClient/src/components/Ellipsis/demo/line.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: 4 | zh-CN: 按照行数省略 5 | en-US: Truncate according to the number of rows 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 通过设置 `lines` 属性指定最大行数,如果超过这个行数的文本会自动截取。但是在这种模式下所有 `children` 将会被转换成纯文本。 11 | 12 | 并且注意在这种模式下,外容器需要有指定的宽度(或设置自身宽度)。 13 | 14 | ## en-US 15 | 16 | `lines` attribute specifies the maximum number of rows where the text will automatically be truncated when exceeded. In this mode, all children will be converted to plain text. 17 | 18 | Also note that, in this mode, the outer container needs to have a specified width (or set its own width). 19 | 20 | 21 | ````jsx 22 | import Ellipsis from 'ant-design-pro/lib/Ellipsis'; 23 | 24 | const article =

There were injuries alleged in three cases in 2015, and a fourth incident in September, according to the safety recall report. After meeting with US regulators in October, the firm decided to issue a voluntary recall.

; 25 | 26 | ReactDOM.render( 27 |
28 | {article} 29 |
30 | , mountNode); 31 | ```` 32 | -------------------------------------------------------------------------------- /server/server/helpers/APIError.js: -------------------------------------------------------------------------------- 1 | const httpStatus = require('http-status'); 2 | 3 | /** 4 | * @extends Error 5 | */ 6 | class ExtendableError extends Error { 7 | constructor(message, status, isPublic) { 8 | super(message); 9 | this.name = this.constructor.name; 10 | this.message = message; 11 | this.status = status; 12 | this.isPublic = isPublic; 13 | this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore. 14 | Error.captureStackTrace(this, this.constructor.name); 15 | } 16 | } 17 | 18 | /** 19 | * Class representing an API error. 20 | * @extends ExtendableError 21 | */ 22 | class APIError extends ExtendableError { 23 | /** 24 | * Creates an API error. 25 | * @param {string} message - Error message. 26 | * @param {number} status - HTTP status code of error. 27 | * @param {boolean} isPublic - Whether the message should be visible to user or not. 28 | */ 29 | constructor(message, status = httpStatus.INTERNAL_SERVER_ERROR, isPublic = false) { 30 | super(message, status, isPublic); 31 | } 32 | } 33 | 34 | 35 | module.exports = APIError; 36 | -------------------------------------------------------------------------------- /antdProClient/src/layouts/Footer.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Layout, Icon } from 'antd'; 3 | import GlobalFooter from '@/components/GlobalFooter'; 4 | 5 | const { Footer } = Layout; 6 | const FooterView = () => ( 7 |
8 | , 19 | // href: 'https://github.com/ant-design/ant-design-pro', 20 | // blankTarget: true, 21 | // }, 22 | // { 23 | // key: 'Ant Design', 24 | // title: 'Ant Design', 25 | // href: 'https://ant.design', 26 | // blankTarget: true, 27 | // }, 28 | // ]} 29 | copyright={ 30 | 31 | Copyright 2018 阿里云OSS 32 | 33 | } 34 | /> 35 |
36 | ); 37 | export default FooterView; 38 | -------------------------------------------------------------------------------- /antdProClient/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alipay.inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/Radar/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .radar { 4 | .legend { 5 | margin-top: 16px; 6 | .legendItem { 7 | position: relative; 8 | text-align: center; 9 | cursor: pointer; 10 | color: @text-color-secondary; 11 | line-height: 22px; 12 | p { 13 | margin: 0; 14 | } 15 | h6 { 16 | color: @heading-color; 17 | padding-left: 16px; 18 | font-size: 24px; 19 | line-height: 32px; 20 | margin-top: 4px; 21 | margin-bottom: 0; 22 | } 23 | &:after { 24 | background-color: @border-color-split; 25 | position: absolute; 26 | top: 8px; 27 | right: 0; 28 | height: 40px; 29 | width: 1px; 30 | content: ''; 31 | } 32 | } 33 | > :last-child .legendItem:after { 34 | display: none; 35 | } 36 | .dot { 37 | border-radius: 6px; 38 | display: inline-block; 39 | margin-right: 6px; 40 | position: relative; 41 | top: -1px; 42 | height: 6px; 43 | width: 6px; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 基本 5 | en-US: Basic 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 基本描述列表。 11 | 12 | ## en-US 13 | 14 | Basic DescriptionList. 15 | 16 | ````jsx 17 | import DescriptionList from 'ant-design-pro/lib/DescriptionList'; 18 | 19 | const { Description } = DescriptionList; 20 | 21 | ReactDOM.render( 22 | 23 | 24 | A free, open source, cross-platform, 25 | graphical web browser developed by the 26 | Mozilla Corporation and hundreds of 27 | volunteers. 28 | 29 | 30 | A free, open source, cross-platform, 31 | graphical web browser developed by the 32 | Mozilla Corporation and hundreds of 33 | volunteers. 34 | 35 | 36 | A free, open source, cross-platform, 37 | graphical web browser developed by the 38 | Mozilla Corporation and hundreds of 39 | volunteers. 40 | 41 | 42 | , mountNode); 43 | ```` 44 | -------------------------------------------------------------------------------- /server/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2017 Kunal Kapadia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/demo/vertical.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: 4 | zh-CN: 垂直型 5 | en-US: Vertical 6 | --- 7 | 8 | ## zh-CN 9 | 10 | 垂直布局。 11 | 12 | ## en-US 13 | 14 | Vertical layout. 15 | 16 | ````jsx 17 | import DescriptionList from 'ant-design-pro/lib/DescriptionList'; 18 | 19 | const { Description } = DescriptionList; 20 | 21 | ReactDOM.render( 22 | 23 | 24 | A free, open source, cross-platform, 25 | graphical web browser developed by the 26 | Mozilla Corporation and hundreds of 27 | volunteers. 28 | 29 | 30 | A free, open source, cross-platform, 31 | graphical web browser developed by the 32 | Mozilla Corporation and hundreds of 33 | volunteers. 34 | 35 | 36 | A free, open source, cross-platform, 37 | graphical web browser developed by the 38 | Mozilla Corporation and hundreds of 39 | volunteers. 40 | 41 | 42 | , mountNode); 43 | ```` 44 | -------------------------------------------------------------------------------- /antdProClient/src/components/TagSelect/demo/expandable.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: 可展开和收起 4 | --- 5 | 6 | 使用 `expandable` 属性,让标签组可以收起,避免过高。 7 | 8 | ````jsx 9 | import TagSelect from 'ant-design-pro/lib/TagSelect'; 10 | 11 | function handleFormSubmit(checkedValue) { 12 | console.log(checkedValue); 13 | } 14 | 15 | ReactDOM.render( 16 | 17 | 类目一 18 | 类目二 19 | 类目三 20 | 类目四 21 | 类目五 22 | 类目六 23 | 类目七 24 | 类目八 25 | 类目九 26 | 类目十 27 | 类目十一 28 | 类目十二 29 | 30 | , mountNode); 31 | ```` 32 | -------------------------------------------------------------------------------- /antdProClient/src/components/SiderMenu/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Drawer } from 'antd'; 3 | import SiderMenu from './SiderMenu'; 4 | 5 | /** 6 | * Recursively flatten the data 7 | * [{path:string},{path:string}] => {path,path2} 8 | * @param menus 9 | */ 10 | const getFlatMenuKeys = menuData => { 11 | let keys = []; 12 | menuData.forEach(item => { 13 | if (item.children) { 14 | keys = keys.concat(getFlatMenuKeys(item.children)); 15 | } 16 | keys.push(item.path); 17 | }); 18 | return keys; 19 | }; 20 | 21 | const SiderMenuWrapper = props => { 22 | const { isMobile, menuData, collapsed, onCollapse } = props; 23 | return isMobile ? ( 24 | onCollapse(true)} 28 | style={{ 29 | padding: 0, 30 | height: '100vh', 31 | }} 32 | > 33 | 38 | 39 | ) : ( 40 | 41 | ); 42 | }; 43 | 44 | export default SiderMenuWrapper; 45 | -------------------------------------------------------------------------------- /antdProClient/src/components/Result/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .result { 4 | text-align: center; 5 | width: 72%; 6 | margin: 0 auto; 7 | @media screen and (max-width: @screen-xs) { 8 | width: 100%; 9 | } 10 | 11 | .icon { 12 | font-size: 72px; 13 | line-height: 72px; 14 | margin-bottom: 24px; 15 | 16 | & > .success { 17 | color: @success-color; 18 | } 19 | 20 | & > .error { 21 | color: @error-color; 22 | } 23 | } 24 | 25 | .title { 26 | font-size: 24px; 27 | color: @heading-color; 28 | font-weight: 500; 29 | line-height: 32px; 30 | margin-bottom: 16px; 31 | } 32 | 33 | .description { 34 | font-size: 14px; 35 | line-height: 22px; 36 | color: @text-color-secondary; 37 | margin-bottom: 24px; 38 | } 39 | 40 | .extra { 41 | background: #fafafa; 42 | padding: 24px 40px; 43 | border-radius: @border-radius-sm; 44 | text-align: left; 45 | 46 | @media screen and (max-width: @screen-xs) { 47 | padding: 18px 20px; 48 | } 49 | } 50 | 51 | .actions { 52 | margin-top: 32px; 53 | 54 | button:not(:last-child) { 55 | margin-right: 8px; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /antdProClient/src/components/AvatarList/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Tooltip, Avatar } from 'antd'; 3 | import classNames from 'classnames'; 4 | 5 | import styles from './index.less'; 6 | 7 | const AvatarList = ({ children, size, ...other }) => { 8 | const childrenWithProps = React.Children.map(children, child => 9 | React.cloneElement(child, { 10 | size, 11 | }) 12 | ); 13 | 14 | return ( 15 |
16 |
    {childrenWithProps}
17 |
18 | ); 19 | }; 20 | 21 | const Item = ({ src, size, tips, onClick = () => {} }) => { 22 | const cls = classNames(styles.avatarItem, { 23 | [styles.avatarItemLarge]: size === 'large', 24 | [styles.avatarItemSmall]: size === 'small', 25 | [styles.avatarItemMini]: size === 'mini', 26 | }); 27 | 28 | return ( 29 |
  • 30 | {tips ? ( 31 | 32 | 33 | 34 | ) : ( 35 | 36 | )} 37 |
  • 38 | ); 39 | }; 40 | 41 | AvatarList.Item = Item; 42 | 43 | export default AvatarList; 44 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/demo/radar.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 7 3 | title: 雷达图 4 | --- 5 | 6 | ````jsx 7 | import { Radar, ChartCard } from 'ant-design-pro/lib/Charts'; 8 | 9 | const radarOriginData = [ 10 | { 11 | name: '个人', 12 | ref: 10, 13 | koubei: 8, 14 | output: 4, 15 | contribute: 5, 16 | hot: 7, 17 | }, 18 | { 19 | name: '团队', 20 | ref: 3, 21 | koubei: 9, 22 | output: 6, 23 | contribute: 3, 24 | hot: 1, 25 | }, 26 | { 27 | name: '部门', 28 | ref: 4, 29 | koubei: 1, 30 | output: 6, 31 | contribute: 5, 32 | hot: 7, 33 | }, 34 | ]; 35 | const radarData = []; 36 | const radarTitleMap = { 37 | ref: '引用', 38 | koubei: '口碑', 39 | output: '产量', 40 | contribute: '贡献', 41 | hot: '热度', 42 | }; 43 | radarOriginData.forEach((item) => { 44 | Object.keys(item).forEach((key) => { 45 | if (key !== 'name') { 46 | radarData.push({ 47 | name: item.name, 48 | label: radarTitleMap[key], 49 | value: item[key], 50 | }); 51 | } 52 | }); 53 | }); 54 | 55 | ReactDOM.render( 56 | 57 | 62 | 63 | , mountNode); 64 | ```` 65 | -------------------------------------------------------------------------------- /antdProClient/tests/run-tests.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process'); 2 | const { kill } = require('cross-port-killer'); 3 | 4 | const env = Object.create(process.env); 5 | env.BROWSER = 'none'; 6 | env.TEST = true; 7 | // flag to prevent multiple test 8 | let once = false; 9 | 10 | const startServer = spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['start'], { 11 | env, 12 | }); 13 | 14 | startServer.stderr.on('data', data => { 15 | // eslint-disable-next-line 16 | console.log(data.toString()); 17 | }); 18 | 19 | startServer.on('exit', () => { 20 | kill(process.env.PORT || 8000); 21 | }); 22 | 23 | // eslint-disable-next-line 24 | console.log('Starting development server for e2e tests...'); 25 | startServer.stdout.on('data', data => { 26 | // eslint-disable-next-line 27 | console.log(data.toString()); 28 | if (!once && data.toString().indexOf('App running at') >= 0) { 29 | // eslint-disable-next-line 30 | once = true; 31 | console.log('Development server is started, ready to run tests.'); 32 | const testCmd = spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['test'], { 33 | stdio: 'inherit', 34 | }); 35 | testCmd.on('exit', code => { 36 | startServer.kill(); 37 | process.exit(code); 38 | }); 39 | } 40 | }); 41 | -------------------------------------------------------------------------------- /antdProClient/src/components/EditableLinkGroup/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent, createElement } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Button } from 'antd'; 4 | import styles from './index.less'; 5 | 6 | // TODO: 添加逻辑 7 | 8 | class EditableLinkGroup extends PureComponent { 9 | static propTypes = { 10 | links: PropTypes.array, 11 | onAdd: PropTypes.func, 12 | linkElement: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), 13 | }; 14 | 15 | static defaultProps = { 16 | links: [], 17 | onAdd: () => {}, 18 | linkElement: 'a', 19 | }; 20 | 21 | render() { 22 | const { links, linkElement, onAdd } = this.props; 23 | return ( 24 |
    25 | {links.map(link => 26 | createElement( 27 | linkElement, 28 | { 29 | key: `linkGroup-item-${link.id || link.title}`, 30 | to: link.href, 31 | href: link.href, 32 | }, 33 | link.title 34 | ) 35 | )} 36 | { 37 | 40 | } 41 |
    42 | ); 43 | } 44 | } 45 | 46 | export default EditableLinkGroup; 47 | -------------------------------------------------------------------------------- /antdProClient/src/components/NumberInfo/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Icon } from 'antd'; 3 | import classNames from 'classnames'; 4 | import styles from './index.less'; 5 | 6 | const NumberInfo = ({ theme, title, subTitle, total, subTotal, status, suffix, gap, ...rest }) => ( 7 |
    13 | {title && ( 14 |
    15 | {title} 16 |
    17 | )} 18 | {subTitle && ( 19 |
    23 | {subTitle} 24 |
    25 | )} 26 |
    27 | 28 | {total} 29 | {suffix && {suffix}} 30 | 31 | {(status || subTotal) && ( 32 | 33 | {subTotal} 34 | {status && } 35 | 36 | )} 37 |
    38 |
    39 | ); 40 | 41 | export default NumberInfo; 42 | -------------------------------------------------------------------------------- /antdProClient/src/components/FooterToolbar/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: 4 | zh-CN: 演示 5 | en-US: demo 6 | iframe: 400 7 | --- 8 | 9 | ## zh-CN 10 | 11 | 浮动固定页脚。 12 | 13 | ## en-US 14 | 15 | Fixed to the footer. 16 | 17 | ````jsx 18 | import FooterToolbar from 'ant-design-pro/lib/FooterToolbar'; 19 | import { Button } from 'antd'; 20 | 21 | ReactDOM.render( 22 |
    23 |

    Content Content Content Content

    24 |

    Content Content Content Content

    25 |

    Content Content Content Content

    26 |

    Content Content Content Content

    27 |

    Content Content Content Content

    28 |

    Content Content Content Content

    29 |

    Content Content Content Content

    30 |

    Content Content Content Content

    31 |

    Content Content Content Content

    32 |

    Content Content Content Content

    33 |

    Content Content Content Content

    34 |

    Content Content Content Content

    35 |

    Content Content Content Content

    36 |

    Content Content Content Content

    37 |

    Content Content Content Content

    38 | 39 | 40 | 41 | 42 |
    43 | , mountNode); 44 | ```` -------------------------------------------------------------------------------- /antdProClient/src/components/Login/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Login 3 | subtitle: 登录 4 | cols: 1 5 | order: 15 6 | --- 7 | 8 | 支持多种登录方式切换,内置了几种常见的登录控件,可以灵活组合,也支持和自定义控件配合使用。 9 | 10 | ## API 11 | 12 | ### Login 13 | 14 | 参数 | 说明 | 类型 | 默认值 15 | ----|------|-----|------ 16 | defaultActiveKey | 默认激活 tab 面板的 key | String | - 17 | onTabChange | 切换页签时的回调 | (key) => void | - 18 | onSubmit | 点击提交时的回调 | (err, values) => void | - 19 | 20 | ### Login.Tab 21 | 22 | 参数 | 说明 | 类型 | 默认值 23 | ----|------|-----|------ 24 | key | 对应选项卡的 key | String | - 25 | tab | 选项卡头显示文字 | ReactNode | - 26 | 27 | ### Login.UserName 28 | 29 | 参数 | 说明 | 类型 | 默认值 30 | ----|------|-----|------ 31 | name | 控件标记,提交数据中同样以此为 key | String | - 32 | rules | 校验规则,同 Form getFieldDecorator(id, options) 中 [option.rules 的规则](getFieldDecorator(id, options)) | object[] | - 33 | 34 | 除上述属性以外,Login.UserName 还支持 antd.Input 的所有属性,并且自带默认的基础配置,包括 `placeholder` `size` `prefix` 等,这些基础配置均可被覆盖。 35 | ## Login.Password、Login.Mobile 同 Login.UserName 36 | 37 | ### Login.Captcha 38 | 39 | 参数 | 说明 | 类型 | 默认值 40 | ----|------|-----|------ 41 | onGetCaptcha | 点击获取校验码的回调 | () => (void \| false \| Promise) | - 42 | countDown | 倒计时 | number |- 43 | buttonText | 点击获取校验码的说明文字 | ReactNode | '获取验证码' 44 | 45 | 除上述属性以外,Login.Captcha 支持的属性与 Login.UserName 相同。 46 | 47 | ### Login.Submit 48 | 49 | 支持 antd.Button 的所有属性。 50 | -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { RouteProps } from 'react-router'; 3 | 4 | type authorityFN = (currentAuthority?: string) => boolean; 5 | 6 | type authority = string | Array | authorityFN | Promise; 7 | 8 | export type IReactComponent

    = 9 | | React.StatelessComponent

    10 | | React.ComponentClass

    11 | | React.ClassicComponentClass

    ; 12 | 13 | interface Secured { 14 | (authority: authority, error?: React.ReactNode): (target: T) => T; 15 | } 16 | 17 | export interface AuthorizedRouteProps extends RouteProps { 18 | authority: authority; 19 | } 20 | export class AuthorizedRoute extends React.Component {} 21 | 22 | interface check { 23 | ( 24 | authority: authority, 25 | target: T, 26 | Exception: S 27 | ): T | S; 28 | } 29 | 30 | export interface AuthorizedProps { 31 | authority: authority; 32 | noMatch?: React.ReactNode; 33 | } 34 | 35 | export class Authorized extends React.Component { 36 | static Secured: Secured; 37 | static AuthorizedRoute: typeof AuthorizedRoute; 38 | static check: check; 39 | } 40 | 41 | declare function renderAuthorize(currentAuthority: string): typeof Authorized; 42 | 43 | export default renderAuthorize; 44 | -------------------------------------------------------------------------------- /server/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | express-mongoose-es6-rest-api: 5 | build: 6 | context: . 7 | volumes: 8 | # Mounts the project directory on the host to /app inside the container, 9 | # allowing you to modify the code without having to rebuild the image. 10 | - .:/app 11 | # Just specify a path and let the Engine create a volume. 12 | # Data present in the base image at the specified mount point will be copied 13 | # over to the new volume upon volume initialization. 14 | # node_modules from this new volume will be used and not from your local dev env. 15 | - /app/node_modules/ 16 | 17 | # Expose ports [HOST:CONTAINER} 18 | ports: 19 | - "4040:4040" 20 | 21 | # Set environment variables from this file 22 | env_file: 23 | - .env 24 | 25 | # Overwrite any env var defined in .env file (if required) 26 | environment: 27 | - MONGO_HOST=mongodb://mongo/express-mongoose-es6-rest-api-development 28 | - DEBUG=express-mongoose-es6-rest-api:* 29 | 30 | # Link to containers in another service. 31 | # Links also express dependency between services in the same way as depends_on, 32 | # so they determine the order of service startup. 33 | links: 34 | - mongo 35 | mongo: 36 | image: "mongo:3.4" 37 | ports: 38 | - "27017:27017" 39 | -------------------------------------------------------------------------------- /antdProClient/config/router.config.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | // app 3 | { 4 | path: '/', 5 | component: '../layouts/BasicLayout', 6 | Routes: ['src/pages/Authorized'], 7 | // authority: ['admin'], 8 | routes: [ 9 | { path: '/', redirect: '/upload' }, 10 | { 11 | path: '/upload', 12 | name: 'upload', 13 | icon: 'read', 14 | component: './Upload' 15 | }, 16 | { 17 | name: 'exception', 18 | icon: 'warning', 19 | path: '/exception', 20 | hideInMenu: true, 21 | routes: [ 22 | // exception 23 | { 24 | path: '/exception/403', 25 | name: 'not-permission', 26 | component: './Exception/403', 27 | }, 28 | { 29 | path: '/exception/404', 30 | name: 'not-find', 31 | component: './Exception/404', 32 | }, 33 | { 34 | path: '/exception/500', 35 | name: 'server-error', 36 | component: './Exception/500', 37 | }, 38 | { 39 | path: '/exception/trigger', 40 | name: 'trigger', 41 | hideInMenu: true, 42 | component: './Exception/TriggerException', 43 | }, 44 | ], 45 | }, 46 | { 47 | component: '404', 48 | }, 49 | ], 50 | } 51 | ]; 52 | -------------------------------------------------------------------------------- /antdProClient/src/components/TopNavHeader/index.less: -------------------------------------------------------------------------------- 1 | .head { 2 | width: 100%; 3 | transition: background 0.3s, width 0.2s; 4 | height: 64px; 5 | padding: 0 12px 0 0; 6 | box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); 7 | position: relative; 8 | :global { 9 | .ant-menu-submenu.ant-menu-submenu-horizontal { 10 | height: 100%; 11 | padding-top: 9px; 12 | .ant-menu-submenu-title { 13 | height: 100%; 14 | } 15 | } 16 | } 17 | &.light { 18 | background-color: #fff; 19 | } 20 | .main { 21 | display: flex; 22 | height: 64px; 23 | padding-left: 24px; 24 | &.wide { 25 | max-width: 1200px; 26 | margin: auto; 27 | padding-left: 4px; 28 | } 29 | .left { 30 | flex: 1; 31 | display: flex; 32 | } 33 | .right { 34 | width: 324px; 35 | } 36 | } 37 | } 38 | 39 | .logo { 40 | width: 165px; 41 | height: 64px; 42 | position: relative; 43 | line-height: 64px; 44 | transition: all 0.3s; 45 | overflow: hidden; 46 | img { 47 | display: inline-block; 48 | vertical-align: middle; 49 | height: 32px; 50 | } 51 | h1 { 52 | color: #fff; 53 | display: inline-block; 54 | vertical-align: middle; 55 | font-size: 16px; 56 | margin: 0 0 0 12px; 57 | font-weight: 400; 58 | } 59 | } 60 | 61 | .light { 62 | h1 { 63 | color: #002140; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/MiniBar/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Chart, Tooltip, Geom } from 'bizcharts'; 3 | import autoHeight from '../autoHeight'; 4 | import styles from '../index.less'; 5 | 6 | @autoHeight() 7 | class MiniBar extends React.Component { 8 | render() { 9 | const { height, forceFit = true, color = '#1890FF', data = [] } = this.props; 10 | 11 | const scale = { 12 | x: { 13 | type: 'cat', 14 | }, 15 | y: { 16 | min: 0, 17 | }, 18 | }; 19 | 20 | const padding = [36, 5, 30, 5]; 21 | 22 | const tooltip = [ 23 | 'x*y', 24 | (x, y) => ({ 25 | name: x, 26 | value: y, 27 | }), 28 | ]; 29 | 30 | // for tooltip not to be hide 31 | const chartHeight = height + 54; 32 | 33 | return ( 34 |

    35 |
    36 | 43 | 44 | 45 | 46 |
    47 |
    48 | ); 49 | } 50 | } 51 | export default MiniBar; 52 | -------------------------------------------------------------------------------- /antdProClient/src/components/SelectLang/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { FormattedMessage, setLocale, getLocale } from 'umi/locale'; 3 | import { Menu, Icon, Dropdown } from 'antd'; 4 | import classNames from 'classnames'; 5 | import styles from './index.less'; 6 | 7 | export default class SelectLang extends PureComponent { 8 | changLang = ({ key }) => { 9 | setLocale(key); 10 | }; 11 | 12 | render() { 13 | const { className } = this.props; 14 | const selectedLang = getLocale(); 15 | const langMenu = ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ); 31 | return ( 32 | 33 | 34 | 35 | 36 | 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /antdProClient/src/pages/Exception/TriggerException.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { Button, Spin, Card } from 'antd'; 3 | import { connect } from 'dva'; 4 | import styles from './style.less'; 5 | 6 | @connect(state => ({ 7 | isloading: state.error.isloading, 8 | })) 9 | class TriggerException extends PureComponent { 10 | state = { 11 | isloading: false, 12 | }; 13 | 14 | triggerError = code => { 15 | this.setState({ 16 | isloading: true, 17 | }); 18 | const { dispatch } = this.props; 19 | dispatch({ 20 | type: 'error/query', 21 | payload: { 22 | code, 23 | }, 24 | }); 25 | }; 26 | 27 | render() { 28 | const { isloading } = this.state; 29 | return ( 30 | 31 | 32 | 35 | 38 | 41 | 44 | 45 | 46 | ); 47 | } 48 | } 49 | 50 | export default TriggerException; 51 | -------------------------------------------------------------------------------- /antdProClient/src/components/GlobalHeader/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { Icon } from 'antd'; 3 | import Link from 'umi/link'; 4 | import Debounce from 'lodash-decorators/debounce'; 5 | import styles from './index.less'; 6 | import RightContent from './RightContent'; 7 | 8 | export default class GlobalHeader extends PureComponent { 9 | componentWillUnmount() { 10 | this.triggerResizeEvent.cancel(); 11 | } 12 | /* eslint-disable*/ 13 | @Debounce(600) 14 | triggerResizeEvent() { 15 | // eslint-disable-line 16 | const event = document.createEvent('HTMLEvents'); 17 | event.initEvent('resize', true, false); 18 | window.dispatchEvent(event); 19 | } 20 | toggle = () => { 21 | const { collapsed, onCollapse } = this.props; 22 | onCollapse(!collapsed); 23 | this.triggerResizeEvent(); 24 | }; 25 | render() { 26 | const { collapsed, isMobile, logo } = this.props; 27 | return ( 28 |
    29 | {isMobile && ( 30 | 31 | logo 32 | 33 | )} 34 | 39 | 40 | 41 |
    42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /antdProClient/src/components/NoticeIcon/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: NoticeIcon 3 | subtitle: 通知菜单 4 | cols: 1 5 | order: 9 6 | --- 7 | 8 | 用在导航工具栏上,作为整个产品统一的通知中心。 9 | 10 | ## API 11 | 12 | 参数 | 说明 | 类型 | 默认值 13 | ----|------|-----|------ 14 | count | 图标上的消息总数 | number | - 15 | bell | translate this please -> Change the bell Icon | ReactNode | `` 16 | loading | 弹出卡片加载状态 | boolean | false 17 | onClear | 点击清空按钮的回调 | function(tabName) | - 18 | onItemClick | 点击列表项的回调 | function(item, tabProps) | - 19 | onTabChange | 切换页签的回调 | function(tabTitle) | - 20 | popupAlign | 弹出卡片的位置配置 | Object [alignConfig](https://github.com/yiminghe/dom-align#alignconfig-object-details) | - 21 | onPopupVisibleChange | 弹出卡片显隐的回调 | function(visible) | - 22 | popupVisible | 控制弹层显隐 | boolean | - 23 | locale | 默认文案 | Object | `{ emptyText: '暂无数据', clear: '清空' }` 24 | 25 | ### NoticeIcon.Tab 26 | 27 | 参数 | 说明 | 类型 | 默认值 28 | ----|------|-----|------ 29 | title | 消息分类的页签标题 | string | - 30 | name | 消息分类的标识符 | string | - 31 | list | 列表数据,格式参照下表 | Array | `[]` 32 | showClear | 是否显示清空按钮 | boolean | true 33 | emptyText | 针对每个 Tab 定制空数据文案 | ReactNode | - 34 | emptyImage | 针对每个 Tab 定制空数据图片 | string | - 35 | 36 | 37 | ### Tab data 38 | 39 | 参数 | 说明 | 类型 | 默认值 40 | ----|------|-----|------ 41 | avatar | 头像图片链接 | string \| ReactNode | - 42 | title | 标题 | ReactNode | - 43 | description | 描述信息 | ReactNode | - 44 | datetime | 时间戳 | ReactNode | - 45 | extra | 额外信息,在列表项右上角 | ReactNode | - 46 | -------------------------------------------------------------------------------- /server/docker-compose.test.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | express-mongoose-es6-rest-api: 5 | build: 6 | context: . 7 | 8 | image: express-mongoose-es6-rest-api:latest 9 | 10 | volumes: 11 | # Mounts the project directory on the host to /app inside the container, 12 | # allowing you to modify the code without having to rebuild the image. 13 | - .:/app 14 | # Just specify a path and let the Engine create a volume. 15 | # Data present in the base image at the specified mount point will be copied 16 | # over to the new volume upon volume initialization. 17 | # node_modules from this new volume will be used and not from your local dev env. 18 | - /app/node_modules/ 19 | 20 | # Set environment variables from this file 21 | env_file: 22 | - .env 23 | 24 | # Overwrite any env var defined in .env file (if required) 25 | environment: 26 | - MONGO_HOST=mongodb://mongo/express-mongoose-es6-rest-api-test 27 | - DEBUG=express-mongoose-es6-rest-api:* 28 | 29 | # Link to containers in another service. 30 | # Links also express dependency between services in the same way as depends_on, 31 | # so they determine the order of service startup. 32 | links: 33 | - mongo 34 | 35 | command: 36 | - /bin/bash 37 | - -c 38 | - yarn --pure-lockfile && yarn test 39 | mongo: 40 | image: "mongo:3.4.2" 41 | ports: 42 | - "27017:27017" 43 | -------------------------------------------------------------------------------- /antdProClient/src/components/TagSelect/demo/controlled.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | title: 受控模式 4 | --- 5 | 6 | 结合 `Tag` 的 `TagSelect` 组件,方便的应用于筛选类目的业务场景中。 7 | 8 | ```jsx 9 | import { Button } from 'antd'; 10 | import TagSelect from 'ant-design-pro/lib/TagSelect'; 11 | 12 | class Demo extends React.Component { 13 | state = { 14 | value: ['cat1'], 15 | }; 16 | handleFormSubmit = value => { 17 | this.setState({ 18 | value, 19 | }); 20 | }; 21 | checkAll = () => { 22 | this.setState({ 23 | value: ['cat1', 'cat2', 'cat3', 'cat4', 'cat5', 'cat6'], 24 | }); 25 | }; 26 | render() { 27 | return ( 28 |
    29 | 30 |
    35 | 36 | 类目一 37 | 类目二 38 | 类目三 39 | 类目四 40 | 类目五 41 | 类目六 42 | 43 |
    44 |
    45 | ); 46 | } 47 | } 48 | 49 | ReactDOM.render(, mountNode); 50 | ``` 51 | -------------------------------------------------------------------------------- /antdProClient/src/components/EditableItem/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { Input, Icon } from 'antd'; 3 | import styles from './index.less'; 4 | 5 | export default class EditableItem extends PureComponent { 6 | constructor(props) { 7 | super(props); 8 | this.state = { 9 | value: props.value, 10 | editable: false, 11 | }; 12 | } 13 | 14 | handleChange = e => { 15 | const { value } = e.target; 16 | this.setState({ value }); 17 | }; 18 | 19 | check = () => { 20 | this.setState({ editable: false }); 21 | const { value } = this.state; 22 | const { onChange } = this.state; 23 | if (onChange) { 24 | onChange(value); 25 | } 26 | }; 27 | 28 | edit = () => { 29 | this.setState({ editable: true }); 30 | }; 31 | 32 | render() { 33 | const { value, editable } = this.state; 34 | return ( 35 |
    36 | {editable ? ( 37 |
    38 | 39 | 40 |
    41 | ) : ( 42 |
    43 | {value || ' '} 44 | 45 |
    46 | )} 47 |
    48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /antdProClient/src/components/PageHeaderWrapper/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { FormattedMessage } from 'umi/locale'; 3 | import Link from 'umi/link'; 4 | import PageHeader from '@/components/PageHeader'; 5 | import { connect } from 'dva'; 6 | import GridContent from './GridContent'; 7 | import styles from './index.less'; 8 | import MenuContext from '@/layouts/MenuContext'; 9 | 10 | const PageHeaderWrapper = ({ children, contentWidth, wrapperClassName, top, ...restProps }) => ( 11 |
    12 | {top} 13 | 14 | {value => ( 15 | } 18 | {...value} 19 | key="pageheader" 20 | {...restProps} 21 | linkElement={Link} 22 | itemRender={item => { 23 | if (item.locale) { 24 | return ; 25 | } 26 | return item.name; 27 | }} 28 | /> 29 | )} 30 | 31 | {children ? ( 32 |
    33 | {children} 34 |
    35 | ) : null} 36 |
    37 | ); 38 | 39 | export default connect(({ setting }) => ({ 40 | contentWidth: setting.contentWidth, 41 | }))(PageHeaderWrapper); 42 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/index.zh-CN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DescriptionList 3 | subtitle: 描述列表 4 | cols: 1 5 | order: 4 6 | --- 7 | 8 | 成组展示多个只读字段,常见于详情页的信息展示。 9 | 10 | ## API 11 | 12 | ### DescriptionList 13 | 14 | | 参数 | 说明 | 类型 | 默认值 | 15 | |----------|------------------------------------------|-------------|-------| 16 | | layout | 布局方式 | Enum{'horizontal', 'vertical'} | 'horizontal' | 17 | | col | 指定信息最多分几列展示,最终一行几列由 col 配置结合[响应式规则](/components/DescriptionList#响应式规则)决定 | number(0 < col <= 4) | 3 | 18 | | title | 列表标题 | ReactNode | - | 19 | | gutter | 列表项间距,单位为 `px` | number | 32 | 20 | | size | 列表型号 | Enum{'large', 'small'} | - | 21 | 22 | #### 响应式规则 23 | 24 | | 窗口宽度 | 展示列数 | 25 | |---------------------|---------------------------------------------| 26 | | `≥768px` | `col` | 27 | | `≥576px` | `col < 2 ? col : 2` | 28 | | `<576px` | `1` | 29 | 30 | ### DescriptionList.Description 31 | 32 | | 参数 | 说明 | 类型 | 默认值 | 33 | |----------|------------------------------------------|-------------|-------| 34 | | term | 列表项标题 | ReactNode | - | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /antdProClient/src/components/FooterToolbar/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | import styles from './index.less'; 5 | 6 | export default class FooterToolbar extends Component { 7 | static contextTypes = { 8 | isMobile: PropTypes.bool, 9 | }; 10 | 11 | state = { 12 | width: undefined, 13 | }; 14 | 15 | componentDidMount() { 16 | window.addEventListener('resize', this.resizeFooterToolbar); 17 | this.resizeFooterToolbar(); 18 | } 19 | 20 | componentWillUnmount() { 21 | window.removeEventListener('resize', this.resizeFooterToolbar); 22 | } 23 | 24 | resizeFooterToolbar = () => { 25 | const sider = document.querySelector('.ant-layout-sider'); 26 | if (sider == null) { 27 | return; 28 | } 29 | const { isMobile } = this.context; 30 | const width = isMobile ? null : `calc(100% - ${sider.style.width})`; 31 | const { width: stateWidth } = this.state; 32 | if (stateWidth !== width) { 33 | this.setState({ width }); 34 | } 35 | }; 36 | 37 | render() { 38 | const { children, className, extra, ...restProps } = this.props; 39 | const { width } = this.state; 40 | return ( 41 |
    42 |
    {extra}
    43 |
    {children}
    44 |
    45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /antdProClient/src/components/PageHeader/index.test.js: -------------------------------------------------------------------------------- 1 | import { getBreadcrumb } from './breadcrumb'; 2 | import { urlToList } from '../_utils/pathTools'; 3 | 4 | const routerData = { 5 | '/dashboard/analysis': { 6 | name: '分析页', 7 | }, 8 | '/userinfo': { 9 | name: '用户列表', 10 | }, 11 | '/userinfo/:id': { 12 | name: '用户信息', 13 | }, 14 | '/userinfo/:id/addr': { 15 | name: '收货订单', 16 | }, 17 | }; 18 | describe('test getBreadcrumb', () => { 19 | it('Simple url', () => { 20 | expect(getBreadcrumb(routerData, '/dashboard/analysis').name).toEqual('分析页'); 21 | }); 22 | it('Parameters url', () => { 23 | expect(getBreadcrumb(routerData, '/userinfo/2144').name).toEqual('用户信息'); 24 | }); 25 | it('The middle parameter url', () => { 26 | expect(getBreadcrumb(routerData, '/userinfo/2144/addr').name).toEqual('收货订单'); 27 | }); 28 | it('Loop through the parameters', () => { 29 | const urlNameList = urlToList('/userinfo/2144/addr').map( 30 | url => getBreadcrumb(routerData, url).name 31 | ); 32 | expect(urlNameList).toEqual(['用户列表', '用户信息', '收货订单']); 33 | }); 34 | 35 | it('a path', () => { 36 | const urlNameList = urlToList('/userinfo').map(url => getBreadcrumb(routerData, url).name); 37 | expect(urlNameList).toEqual(['用户列表']); 38 | }); 39 | it('Secondary path', () => { 40 | const urlNameList = urlToList('/userinfo/2144').map(url => getBreadcrumb(routerData, url).name); 41 | expect(urlNameList).toEqual(['用户列表', '用户信息']); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /antdProClient/src/layouts/UserLayout.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .container { 4 | display: flex; 5 | flex-direction: column; 6 | height: 100vh; 7 | overflow: auto; 8 | background: @layout-body-background; 9 | } 10 | 11 | .lang { 12 | text-align: right; 13 | width: 100%; 14 | height: 40px; 15 | line-height: 44px; 16 | :global(.ant-dropdown-trigger) { 17 | margin-right: 24px; 18 | } 19 | } 20 | 21 | .content { 22 | padding: 32px 0; 23 | flex: 1; 24 | } 25 | 26 | @media (min-width: @screen-md-min) { 27 | .container { 28 | background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg'); 29 | background-repeat: no-repeat; 30 | background-position: center 110px; 31 | background-size: 100%; 32 | } 33 | 34 | .content { 35 | padding: 72px 0 24px 0; 36 | } 37 | } 38 | 39 | .top { 40 | text-align: center; 41 | } 42 | 43 | .header { 44 | height: 44px; 45 | line-height: 44px; 46 | a { 47 | text-decoration: none; 48 | } 49 | } 50 | 51 | .logo { 52 | height: 44px; 53 | vertical-align: top; 54 | margin-right: 16px; 55 | } 56 | 57 | .title { 58 | font-size: 33px; 59 | color: @heading-color; 60 | font-family: 'Myriad Pro', 'Helvetica Neue', Arial, Helvetica, sans-serif; 61 | font-weight: 600; 62 | position: relative; 63 | top: 2px; 64 | } 65 | 66 | .desc { 67 | font-size: @font-size-base; 68 | color: @text-color-secondary; 69 | margin-top: 12px; 70 | margin-bottom: 40px; 71 | } 72 | -------------------------------------------------------------------------------- /antdProClient/src/e2e/login.e2e.js: -------------------------------------------------------------------------------- 1 | import puppeteer from 'puppeteer'; 2 | 3 | describe('Login', () => { 4 | let browser; 5 | let page; 6 | 7 | beforeAll(async () => { 8 | browser = await puppeteer.launch({ args: ['--no-sandbox'] }); 9 | }); 10 | 11 | beforeEach(async () => { 12 | page = await browser.newPage(); 13 | await page.goto('http://localhost:8000/user/login', { waitUntil: 'networkidle2' }); 14 | await page.evaluate(() => window.localStorage.setItem('cnuip-company-patent-store-authority', 'guest')); 15 | }); 16 | 17 | afterEach(() => page.close()); 18 | 19 | it('should login with failure', async () => { 20 | await page.waitForSelector('#userName', { 21 | timeout: 2000, 22 | }); 23 | await page.type('#userName', 'mockuser'); 24 | await page.type('#password', 'wrong_password'); 25 | await page.click('button[type="submit"]'); 26 | await page.waitForSelector('.ant-alert-error'); // should display error 27 | }); 28 | 29 | it('should login successfully', async () => { 30 | await page.waitForSelector('#userName', { 31 | timeout: 2000, 32 | }); 33 | await page.type('#userName', 'admin'); 34 | await page.type('#password', '888888'); 35 | await page.click('button[type="submit"]'); 36 | await page.waitForSelector('.ant-layout-sider h1'); // should display error 37 | const text = await page.evaluate(() => document.body.innerHTML); 38 | expect(text).toContain('

    Ant Design Pro

    '); 39 | }); 40 | 41 | afterAll(() => browser.close()); 42 | }); 43 | -------------------------------------------------------------------------------- /antdProClient/src/components/Login/map.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Icon } from 'antd'; 3 | import styles from './index.less'; 4 | 5 | export default { 6 | UserName: { 7 | props: { 8 | size: 'large', 9 | prefix: , 10 | placeholder: 'admin', 11 | }, 12 | rules: [ 13 | { 14 | required: true, 15 | message: 'Please enter username!', 16 | }, 17 | ], 18 | }, 19 | Password: { 20 | props: { 21 | size: 'large', 22 | prefix: , 23 | type: 'password', 24 | placeholder: '888888', 25 | }, 26 | rules: [ 27 | { 28 | required: true, 29 | message: 'Please enter password!', 30 | }, 31 | ], 32 | }, 33 | Mobile: { 34 | props: { 35 | size: 'large', 36 | prefix: , 37 | placeholder: 'mobile number', 38 | }, 39 | rules: [ 40 | { 41 | required: true, 42 | message: 'Please enter mobile number!', 43 | }, 44 | { 45 | pattern: /^1\d{10}$/, 46 | message: 'Wrong mobile number format!', 47 | }, 48 | ], 49 | }, 50 | Captcha: { 51 | props: { 52 | size: 'large', 53 | prefix: , 54 | placeholder: 'captcha', 55 | }, 56 | rules: [ 57 | { 58 | required: true, 59 | message: 'Please enter Captcha!', 60 | }, 61 | ], 62 | }, 63 | }; 64 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/autoHeight.js: -------------------------------------------------------------------------------- 1 | /* eslint eqeqeq: 0 */ 2 | import React from 'react'; 3 | 4 | function computeHeight(node) { 5 | const totalHeight = parseInt(getComputedStyle(node).height, 10); 6 | const padding = 7 | parseInt(getComputedStyle(node).paddingTop, 10) + 8 | parseInt(getComputedStyle(node).paddingBottom, 10); 9 | return totalHeight - padding; 10 | } 11 | 12 | function getAutoHeight(n) { 13 | if (!n) { 14 | return 0; 15 | } 16 | 17 | let node = n; 18 | 19 | let height = computeHeight(node); 20 | 21 | while (!height) { 22 | node = node.parentNode; 23 | if (node) { 24 | height = computeHeight(node); 25 | } else { 26 | break; 27 | } 28 | } 29 | 30 | return height; 31 | } 32 | 33 | const autoHeight = () => WrappedComponent => 34 | class extends React.Component { 35 | state = { 36 | computedHeight: 0, 37 | }; 38 | 39 | componentDidMount() { 40 | const { height } = this.props; 41 | if (!height) { 42 | const h = getAutoHeight(this.root); 43 | // eslint-disable-next-line 44 | this.setState({ computedHeight: h }); 45 | } 46 | } 47 | 48 | handleRoot = node => { 49 | this.root = node; 50 | }; 51 | 52 | render() { 53 | const { height } = this.props; 54 | const { computedHeight } = this.state; 55 | const h = height || computedHeight; 56 | return ( 57 |
    {h > 0 && }
    58 | ); 59 | } 60 | }; 61 | 62 | export default autoHeight; 63 | -------------------------------------------------------------------------------- /antdProClient/src/components/StandardFormRow/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .standardFormRow { 4 | border-bottom: 1px dashed @border-color-split; 5 | padding-bottom: 16px; 6 | margin-bottom: 16px; 7 | display: flex; 8 | :global { 9 | .ant-form-item { 10 | margin-right: 24px; 11 | } 12 | .ant-form-item-label label { 13 | color: @text-color; 14 | margin-right: 0; 15 | } 16 | .ant-form-item-label, 17 | .ant-form-item-control { 18 | padding: 0; 19 | line-height: 32px; 20 | } 21 | } 22 | .label { 23 | color: @heading-color; 24 | font-size: @font-size-base; 25 | margin-right: 24px; 26 | flex: 0 0 auto; 27 | text-align: right; 28 | & > span { 29 | display: inline-block; 30 | height: 32px; 31 | line-height: 32px; 32 | &:after { 33 | content: ':'; 34 | } 35 | } 36 | } 37 | .content { 38 | flex: 1 1 0; 39 | :global { 40 | .ant-form-item:last-child { 41 | margin-right: 0; 42 | } 43 | } 44 | } 45 | } 46 | 47 | .standardFormRowLast { 48 | border: none; 49 | padding-bottom: 0; 50 | margin-bottom: 0; 51 | } 52 | 53 | .standardFormRowBlock { 54 | :global { 55 | .ant-form-item, 56 | div.ant-form-item-control-wrapper { 57 | display: block; 58 | } 59 | } 60 | } 61 | 62 | .standardFormRowGrid { 63 | :global { 64 | .ant-form-item, 65 | div.ant-form-item-control-wrapper { 66 | display: block; 67 | } 68 | .ant-form-item-label { 69 | float: left; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /antdProClient/src/components/SettingDrawer/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .content { 4 | min-height: 100%; 5 | background: #fff; 6 | position: relative; 7 | } 8 | 9 | .blockChecbox { 10 | display: flex; 11 | .item { 12 | margin-right: 16px; 13 | position: relative; 14 | // box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); 15 | border-radius: @border-radius-base; 16 | cursor: pointer; 17 | img { 18 | width: 48px; 19 | } 20 | } 21 | .selectIcon { 22 | position: absolute; 23 | top: 0; 24 | right: 0; 25 | width: 100%; 26 | padding-top: 15px; 27 | padding-left: 24px; 28 | height: 100%; 29 | color: @primary-color; 30 | font-size: 14px; 31 | font-weight: bold; 32 | } 33 | } 34 | 35 | .color_block { 36 | width: 38px; 37 | height: 22px; 38 | margin: 4px; 39 | border-radius: 4px; 40 | cursor: pointer; 41 | margin-right: 12px; 42 | display: inline-block; 43 | vertical-align: middle; 44 | } 45 | 46 | .title { 47 | font-size: 14px; 48 | color: @heading-color; 49 | line-height: 22px; 50 | margin-bottom: 12px; 51 | } 52 | 53 | .handle { 54 | position: absolute; 55 | top: 240px; 56 | background: @primary-color; 57 | width: 48px; 58 | height: 48px; 59 | right: 300px; 60 | display: flex; 61 | justify-content: center; 62 | align-items: center; 63 | cursor: pointer; 64 | pointer-events: auto; 65 | z-index: 0; 66 | text-align: center; 67 | font-size: 16px; 68 | border-radius: 4px 0 0 4px; 69 | } 70 | 71 | .productionHint { 72 | font-size: 12px; 73 | margin-top: 16px; 74 | } 75 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .descriptionList { 4 | // offset the padding-bottom of last row 5 | :global { 6 | .ant-row { 7 | margin-bottom: -16px; 8 | overflow: hidden; 9 | } 10 | } 11 | 12 | .title { 13 | font-size: 14px; 14 | color: @heading-color; 15 | font-weight: 500; 16 | margin-bottom: 16px; 17 | } 18 | 19 | .term { 20 | // Line-height is 22px IE dom height will calculate error 21 | line-height: 20px; 22 | padding-bottom: 16px; 23 | margin-right: 8px; 24 | color: @heading-color; 25 | white-space: nowrap; 26 | display: table-cell; 27 | 28 | &:after { 29 | content: ':'; 30 | margin: 0 8px 0 2px; 31 | position: relative; 32 | top: -0.5px; 33 | } 34 | } 35 | 36 | .detail { 37 | line-height: 20px; 38 | width: 100%; 39 | padding-bottom: 16px; 40 | color: @text-color; 41 | display: table-cell; 42 | } 43 | 44 | &.small { 45 | // offset the padding-bottom of last row 46 | :global { 47 | .ant-row { 48 | margin-bottom: -8px; 49 | } 50 | } 51 | .title { 52 | margin-bottom: 12px; 53 | color: @text-color; 54 | } 55 | .term, 56 | .detail { 57 | padding-bottom: 8px; 58 | } 59 | } 60 | 61 | &.large { 62 | .title { 63 | font-size: 16px; 64 | } 65 | } 66 | 67 | &.vertical { 68 | .term { 69 | padding-bottom: 8px; 70 | display: block; 71 | } 72 | 73 | .detail { 74 | display: block; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /antdProClient/src/components/Charts/ChartCard/index.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .chartCard { 4 | position: relative; 5 | .chartTop { 6 | position: relative; 7 | overflow: hidden; 8 | width: 100%; 9 | } 10 | .chartTopMargin { 11 | margin-bottom: 12px; 12 | } 13 | .chartTopHasMargin { 14 | margin-bottom: 20px; 15 | } 16 | .metaWrap { 17 | float: left; 18 | } 19 | .avatar { 20 | position: relative; 21 | top: 4px; 22 | float: left; 23 | margin-right: 20px; 24 | img { 25 | border-radius: 100%; 26 | } 27 | } 28 | .meta { 29 | color: @text-color-secondary; 30 | font-size: @font-size-base; 31 | line-height: 22px; 32 | height: 22px; 33 | } 34 | .action { 35 | cursor: pointer; 36 | position: absolute; 37 | top: 0; 38 | right: 0; 39 | } 40 | .total { 41 | overflow: hidden; 42 | text-overflow: ellipsis; 43 | word-break: break-all; 44 | white-space: nowrap; 45 | color: @heading-color; 46 | margin-top: 4px; 47 | margin-bottom: 0; 48 | font-size: 30px; 49 | line-height: 38px; 50 | height: 38px; 51 | } 52 | .content { 53 | margin-bottom: 12px; 54 | position: relative; 55 | width: 100%; 56 | } 57 | .contentFixed { 58 | position: absolute; 59 | left: 0; 60 | bottom: 0; 61 | width: 100%; 62 | } 63 | .footer { 64 | border-top: 1px solid @border-color-split; 65 | padding-top: 9px; 66 | margin-top: 8px; 67 | & > * { 68 | position: relative; 69 | } 70 | } 71 | .footerMargin { 72 | margin-top: 20px; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /server/pages/5.async.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([[5],{GsTM:function(e,t,r){"use strict";var n=r("g09b"),a=r("tAuX");Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0,r("IzEo");var u=n(r("bx4M"));r("T2oS");var o=n(r("W9HT"));r("+L6B");var i,l,d,f=n(r("2/Rp")),c=n(r("2Taf")),g=n(r("vZ4D")),s=n(r("l4Ni")),p=n(r("ujKo")),v=n(r("MhPg")),y=a(r("q1tI")),E=r("MuoO"),h=n(r("uUKN")),m=(i=(0,E.connect)(function(e){return{isloading:e.error.isloading}}),i((d=function(e){function t(){var e,r;(0,c.default)(this,t);for(var n=arguments.length,a=new Array(n),u=0;u span { 34 | color: @heading-color; 35 | display: inline-block; 36 | line-height: 32px; 37 | height: 32px; 38 | font-size: 24px; 39 | margin-right: 32px; 40 | } 41 | .subTotal { 42 | color: @text-color-secondary; 43 | font-size: @font-size-lg; 44 | vertical-align: top; 45 | margin-right: 0; 46 | i { 47 | font-size: 12px; 48 | transform: scale(0.82); 49 | margin-left: 4px; 50 | } 51 | :global { 52 | .anticon-caret-up { 53 | color: @red-6; 54 | } 55 | .anticon-caret-down { 56 | color: @green-6; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | .numberInfolight { 63 | .numberInfoValue { 64 | & > span { 65 | color: @text-color; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /antdProClient/src/components/DescriptionList/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DescriptionList 3 | cols: 1 4 | order: 4 5 | --- 6 | 7 | Groups display multiple read-only fields, which are common to informational displays on detail pages. 8 | 9 | ## API 10 | 11 | ### DescriptionList 12 | 13 | | Property | Description | Type | Default | 14 | |----------|------------------------------------------|-------------|---------| 15 | | layout | type of layout | Enum{'horizontal', 'vertical'} | 'horizontal' | 16 | | col | specify the maximum number of columns to display, the final columns number is determined by col setting combined with [Responsive Rules](/components/DescriptionList#Responsive-Rules) | number(0 < col <= 4) | 3 | 17 | | title | title | ReactNode | - | 18 | | gutter | specify the distance between two items, unit is `px` | number | 32 | 19 | | size | size of list | Enum{'large', 'small'} | - | 20 | 21 | #### Responsive Rules 22 | 23 | | Window Width | Columns Number | 24 | |---------------------|---------------------------------------------| 25 | | `≥768px` | `col` | 26 | | `≥576px` | `col < 2 ? col : 2` | 27 | | `<576px` | `1` | 28 | 29 | ### DescriptionList.Description 30 | 31 | | Property | Description | Type | Default | 32 | |----------|------------------------------------------|-------------|-------| 33 | | term | item title | ReactNode | - | 34 | -------------------------------------------------------------------------------- /antdProClient/src/components/PageHeader/demo/structure.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 0 3 | title: Structure 4 | --- 5 | 6 | 基本结构,具备响应式布局功能,主要断点为 768px 和 576px,拖动窗口改变大小试试看。 7 | 8 | ````jsx 9 | import PageHeader from 'ant-design-pro/lib/PageHeader'; 10 | 11 | const breadcrumbList = [{ 12 | title: '面包屑', 13 | }]; 14 | 15 | const tabList = [{ 16 | key: '1', 17 | tab: '页签一', 18 | }, { 19 | key: '2', 20 | tab: '页签二', 21 | }, { 22 | key: '3', 23 | tab: '页签三', 24 | }]; 25 | 26 | ReactDOM.render( 27 |
    28 | Title
    } 31 | logo={
    logo
    } 32 | action={
    action
    } 33 | content={
    content
    } 34 | extraContent={
    extraContent
    } 35 | breadcrumbList={breadcrumbList} 36 | tabList={tabList} 37 | tabActiveKey="1" 38 | /> 39 |
    40 | , mountNode); 41 | ```` 42 | 43 | 69 | -------------------------------------------------------------------------------- /antdProClient/src/components/TopNavHeader/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import Link from 'umi/link'; 3 | import RightContent from '../GlobalHeader/RightContent'; 4 | import BaseMenu from '../SiderMenu/BaseMenu'; 5 | import styles from './index.less'; 6 | 7 | export default class TopNavHeader extends PureComponent { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.state = { 12 | maxWidth: (props.contentWidth === 'Fixed' ? 1200 : window.innerWidth) - 330 - 165 - 4 - 36, 13 | }; 14 | } 15 | 16 | static getDerivedStateFromProps(props) { 17 | return { 18 | maxWidth: (props.contentWidth === 'Fixed' ? 1200 : window.innerWidth) - 330 - 165 - 4 - 36, 19 | }; 20 | } 21 | 22 | render() { 23 | const { theme, contentWidth, logo } = this.props; 24 | const { maxWidth } = this.state; 25 | return ( 26 |
    27 |
    { 29 | this.maim = ref; 30 | }} 31 | className={`${styles.main} ${contentWidth === 'Fixed' ? styles.wide : ''}`} 32 | > 33 |
    34 | 40 |
    45 | 46 |
    47 |
    48 | 49 |
    50 |
    51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /antdProClient/src/components/Exception/index.js: -------------------------------------------------------------------------------- 1 | import React, { createElement } from 'react'; 2 | import classNames from 'classnames'; 3 | import { Button } from 'antd'; 4 | import config from './typeConfig'; 5 | import styles from './index.less'; 6 | 7 | class Exception extends React.PureComponent { 8 | static defaultProps = { 9 | backText: 'back to home', 10 | redirect: '/', 11 | }; 12 | 13 | constructor(props) { 14 | super(props); 15 | this.state = {}; 16 | } 17 | 18 | render() { 19 | const { 20 | className, 21 | backText, 22 | linkElement = 'a', 23 | type, 24 | title, 25 | desc, 26 | img, 27 | actions, 28 | redirect, 29 | ...rest 30 | } = this.props; 31 | const pageType = type in config ? type : '404'; 32 | const clsString = classNames(styles.exception, className); 33 | return ( 34 |
    35 |
    36 |
    40 |
    41 |
    42 |

    {title || config[pageType].title}

    43 |
    {desc || config[pageType].desc}
    44 |
    45 | {actions || 46 | createElement( 47 | linkElement, 48 | { 49 | to: redirect, 50 | href: redirect, 51 | }, 52 | 53 | )} 54 |
    55 |
    56 |
    57 | ); 58 | } 59 | } 60 | 61 | export default Exception; 62 | -------------------------------------------------------------------------------- /antdProClient/src/components/NoticeIcon/NoticeList.less: -------------------------------------------------------------------------------- 1 | @import '~antd/lib/style/themes/default.less'; 2 | 3 | .list { 4 | max-height: 400px; 5 | overflow: auto; 6 | .item { 7 | transition: all 0.3s; 8 | overflow: hidden; 9 | cursor: pointer; 10 | padding-left: 24px; 11 | padding-right: 24px; 12 | 13 | .meta { 14 | width: 100%; 15 | } 16 | 17 | .avatar { 18 | background: #fff; 19 | margin-top: 4px; 20 | } 21 | .iconElement { 22 | font-size: 32px; 23 | } 24 | 25 | &.read { 26 | opacity: 0.4; 27 | } 28 | &:last-child { 29 | border-bottom: 0; 30 | } 31 | &:hover { 32 | background: @primary-1; 33 | } 34 | .title { 35 | font-weight: normal; 36 | margin-bottom: 8px; 37 | } 38 | .description { 39 | font-size: 12px; 40 | line-height: @line-height-base; 41 | } 42 | .datetime { 43 | font-size: 12px; 44 | margin-top: 4px; 45 | line-height: @line-height-base; 46 | } 47 | .extra { 48 | float: right; 49 | color: @text-color-secondary; 50 | font-weight: normal; 51 | margin-right: 0; 52 | margin-top: -1.5px; 53 | } 54 | } 55 | } 56 | 57 | .notFound { 58 | text-align: center; 59 | padding: 73px 0 88px 0; 60 | color: @text-color-secondary; 61 | img { 62 | display: inline-block; 63 | margin-bottom: 16px; 64 | height: 76px; 65 | } 66 | } 67 | 68 | .clear { 69 | height: 46px; 70 | line-height: 46px; 71 | text-align: center; 72 | color: @text-color; 73 | border-radius: 0 0 @border-radius-base @border-radius-base; 74 | border-top: 1px solid @border-color-split; 75 | transition: all 0.3s; 76 | cursor: pointer; 77 | 78 | &:hover { 79 | color: @heading-color; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /antdProClient/src/components/Authorized/PromiseRender.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Spin } from 'antd'; 3 | 4 | export default class PromiseRender extends React.PureComponent { 5 | state = { 6 | component: null, 7 | }; 8 | 9 | componentDidMount() { 10 | this.setRenderComponent(this.props); 11 | } 12 | 13 | componentDidUpdate(nextProps) { 14 | // new Props enter 15 | this.setRenderComponent(nextProps); 16 | } 17 | 18 | // set render Component : ok or error 19 | setRenderComponent(props) { 20 | const ok = this.checkIsInstantiation(props.ok); 21 | const error = this.checkIsInstantiation(props.error); 22 | props.promise 23 | .then(() => { 24 | this.setState({ 25 | component: ok, 26 | }); 27 | }) 28 | .catch(() => { 29 | this.setState({ 30 | component: error, 31 | }); 32 | }); 33 | } 34 | 35 | // Determine whether the incoming component has been instantiated 36 | // AuthorizedRoute is already instantiated 37 | // Authorized render is already instantiated, children is no instantiated 38 | // Secured is not instantiated 39 | checkIsInstantiation = target => { 40 | if (!React.isValidElement(target)) { 41 | return target; 42 | } 43 | return () => target; 44 | }; 45 | 46 | render() { 47 | const { component: Component } = this.state; 48 | const { ok, error, promise, ...rest } = this.props; 49 | return Component ? ( 50 | 51 | ) : ( 52 |
    61 | 62 |
    63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /antdProClient/src/e2e/layout.e2e.js: -------------------------------------------------------------------------------- 1 | import puppeteer from 'puppeteer'; 2 | import RouterConfig from '../../config/router.config'; 3 | 4 | function formatter(data) { 5 | return data 6 | .reduce((pre, item) => { 7 | if (item.routes) { 8 | return pre.concat(formatter(item.routes)); 9 | } 10 | pre.push(item.path); 11 | return pre; 12 | }, []) 13 | .filter(item => item); 14 | } 15 | 16 | describe('Homepage', () => { 17 | let browser; 18 | let page; 19 | 20 | const testAllPage = async layout => 21 | new Promise(async (resolve, reject) => { 22 | const loadPage = async index => { 23 | const path = layout[index]; 24 | try { 25 | await page.goto(`http://localhost:8000${path}`, { waitUntil: 'networkidle2' }); 26 | const haveFooter = await page.evaluate( 27 | () => document.getElementsByTagName('footer').length > 0 28 | ); 29 | 30 | expect(haveFooter).toBeTruthy(); 31 | 32 | if (index < layout.length - 1) { 33 | loadPage(index + 1); 34 | } else { 35 | resolve('ok'); 36 | } 37 | } catch (error) { 38 | reject(error); 39 | } 40 | }; 41 | loadPage(0); 42 | }); 43 | 44 | beforeAll(async () => { 45 | browser = await puppeteer.launch({ args: ['--no-sandbox'] }); 46 | page = await browser.newPage(); 47 | jest.setTimeout(1000000); 48 | }); 49 | 50 | it('test user layout', async () => { 51 | const userLayout = formatter(RouterConfig[0].routes); 52 | await testAllPage(userLayout); 53 | }); 54 | 55 | it('test base layout', async () => { 56 | const baseLayout = formatter(RouterConfig[1].routes); 57 | await testAllPage(baseLayout); 58 | }); 59 | 60 | afterAll(() => browser.close()); 61 | }); 62 | --------------------------------------------------------------------------------