diff --git a/.eslintignore b/.eslintignore index 03232aefb1..966421f477 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,3 @@ /lambda/ /scripts -/config \ No newline at end of file +/config diff --git a/.eslintrc.js b/.eslintrc.js index 30e4710707..7372d96bce 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,8 +10,8 @@ module.exports = { jasmine: true, }, globals: { - ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true, // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 page: true, + ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true, }, rules: { 'react/jsx-filename-extension': [1, { extensions: ['.js'] }], @@ -35,6 +35,8 @@ module.exports = { 'linebreak-style': 0, }, settings: { + // support import modules from TypeScript files in JavaScript files + 'import/resolver': { node: { extensions: ['.js', '.ts', '.tsx'] } }, polyfills: ['fetch', 'promises', 'url', 'object-assign'], }, }; diff --git a/.gitignore b/.gitignore index 253591b520..67e95cb3fc 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,6 @@ package-lock.json .history *.log functions/* -lambda/mock/index.js .temp/** # umi diff --git a/.prettierrc b/.prettierrc index fdcf70e96a..3dc446bfad 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,12 +1,14 @@ { "singleQuote": true, - "trailingComma": "es5", + "trailingComma": "all", "printWidth": 100, "proseWrap": "never", "overrides": [ { "files": ".prettierrc", - "options": { "parser": "json" } + "options": { + "parser": "json" + } } ] -} +} \ No newline at end of file diff --git a/.stylelintrc.json b/.stylelintrc.json index 215bf08119..d366a141fc 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -5,9 +5,12 @@ "stylelint-config-rational-order", "stylelint-config-prettier" ], - "plugins": ["stylelint-order", "stylelint-declaration-block-no-ignored-properties"], + "plugins": [ + "stylelint-order", + "stylelint-declaration-block-no-ignored-properties" + ], "rules": { "no-descending-specificity": null, "plugin/declaration-block-no-ignored-properties": true } -} +} \ No newline at end of file diff --git a/config/config.js b/config/config.ts similarity index 62% rename from config/config.js rename to config/config.ts index 47166e9334..b7d2a6f0d0 100644 --- a/config/config.js +++ b/config/config.ts @@ -1,15 +1,16 @@ // https://umijs.org/config/ import os from 'os'; -import pageRoutes from './router.config'; -import webpackPlugin from './plugin.config'; -import defaultSettings from '../src/defaultSettings'; import slash from 'slash2'; - +import { IPlugin, IConfig } from 'umi-types'; +import defaultSettings from './defaultSettings'; +import webpackPlugin from './plugin.config'; const { pwa, primaryColor } = defaultSettings; -// preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 -const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION, TEST } = process.env; -const plugins = [ +// preview.pro.ant.design only do not use in your production ; +// preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 + +const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION, TEST, NODE_ENV } = process.env; +const plugins: IPlugin[] = [ [ 'umi-plugin-react', { @@ -18,9 +19,12 @@ const plugins = [ hmr: true, }, locale: { - enable: true, // default false - default: 'zh-CN', // default zh-CN - baseNavigator: true, // default true, when it is true, will use `navigator.language` overwrite default + // default false + enable: true, + // default zh-CN + default: 'zh-CN', + // default true, when it is true, will use `navigator.language` overwrite default + baseNavigator: true, }, dynamicImport: { loadingComponent: './components/PageLoading/index', @@ -46,10 +50,18 @@ const plugins = [ : {}), }, ], -]; - -// 针对 preview.pro.ant.design 的 GA 统计代码 + [ + 'umi-plugin-pro-block', + { + moveMock: false, + moveService: false, + modifyRequest: true, + autoAddMenu: true, + }, + ], +]; // 针对 preview.pro.ant.design 的 GA 统计代码 // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 + if (ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') { plugins.push([ 'umi-plugin-ga', @@ -59,6 +71,18 @@ if (ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') { ]); } +const uglifyJSOptions = + NODE_ENV === 'production' + ? { + uglifyOptions: { + // remove console.* except console.error + compress: { + drop_console: true, + pure_funcs: ['console.error'], + }, + }, + } + : {}; export default { // add for transfer to umi plugins, @@ -72,7 +96,22 @@ export default { }, devtool: ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION ? 'source-map' : false, // 路由配置 - routes: pageRoutes, + routes: [ + { + path: '/', + component: '../layouts/BasicLayout', + Routes: ['src/pages/Authorized'], + authority: ['admin', 'user'], + routes: [ + { + path: '/', + name: 'welcome', + icon: 'smile', + component: './Welcome', + }, + ], + }, + ], // Theme for antd // https://ant.design/docs/react/customize-theme-cn theme: { @@ -92,7 +131,13 @@ export default { disableRedirectHoist: true, cssLoaderOptions: { modules: true, - getLocalIdent: (context, localIdentName, localName) => { + getLocalIdent: ( + context: { + resourcePath: string; + }, + localIdentName: string, + localName: string, + ) => { if ( context.resourcePath.includes('node_modules') || context.resourcePath.includes('ant.design.pro.less') || @@ -100,21 +145,24 @@ export default { ) { return localName; } + const match = context.resourcePath.match(/src(.*)/); + if (match && match[1]) { const antdProPath = match[1].replace('.less', ''); const arr = slash(antdProPath) .split('/') - .map(a => a.replace(/([A-Z])/g, '-$1')) - .map(a => a.toLowerCase()); + .map((a: string) => a.replace(/([A-Z])/g, '-$1')) + .map((a: string) => a.toLowerCase()); return `antd-pro${arr.join('-')}-${localName}`.replace(/--/g, '-'); } + return localName; }, }, manifest: { basePath: '/', }, - + uglifyJSOptions, chainWebpack: webpackPlugin, -}; +} as IConfig; diff --git a/config/defaultSettings.ts b/config/defaultSettings.ts new file mode 100644 index 0000000000..4b2c53c6cc --- /dev/null +++ b/config/defaultSettings.ts @@ -0,0 +1,60 @@ +import { MenuTheme } from 'antd/es/menu'; + +export type ContentWidth = 'Fluid' | 'Fixed'; + +export interface DefaultSettings { + /** + * theme for nav menu + */ + navTheme: MenuTheme; + /** + * primary color of ant design + */ + primaryColor: string; + /** + * nav menu position: `sidemenu` or `topmenu` + */ + layout: 'sidemenu' | 'topmenu'; + /** + * layout of content: `Fluid` or `Fixed`, only works when layout is topmenu + */ + contentWidth: ContentWidth; + /** + * sticky header + */ + fixedHeader: boolean; + /** + * auto hide header + */ + autoHideHeader: boolean; + /** + * sticky siderbar + */ + fixSiderbar: boolean; + menu: { locale: boolean }; + title: string; + pwa: boolean; + // Your custom iconfont Symbol script Url + // eg://at.alicdn.com/t/font_1039637_btcrd5co4w.js + // 注意:如果需要图标多色,Iconfont 图标项目里要进行批量去色处理 + // Usage: https://github.com/ant-design/ant-design-pro/pull/3517 + iconfontUrl: string; + colorWeak: boolean; +} + +export default { + navTheme: 'dark', + primaryColor: '#1890FF', + layout: 'sidemenu', + contentWidth: 'Fluid', + fixedHeader: false, + autoHideHeader: false, + fixSiderbar: false, + colorWeak: false, + menu: { + locale: true, + }, + title: 'Ant Design Pro', + pwa: false, + iconfontUrl: '', +} as DefaultSettings; diff --git a/config/plugin.config.js b/config/plugin.config.ts similarity index 81% rename from config/plugin.config.js rename to config/plugin.config.ts index 59ce550f42..d9d150bc00 100644 --- a/config/plugin.config.js +++ b/config/plugin.config.ts @@ -4,7 +4,7 @@ import MergeLessPlugin from 'antd-pro-merge-less'; import AntDesignThemePlugin from 'antd-theme-webpack-plugin'; import path from 'path'; -function getModulePackageName(module) { +function getModulePackageName(module: { context: string }) { if (!module.context) return null; const nodeModulesPath = path.join(__dirname, '../node_modules/'); @@ -14,16 +14,16 @@ function getModulePackageName(module) { const moduleRelativePath = module.context.substring(nodeModulesPath.length); const [moduleDirName] = moduleRelativePath.split(path.sep); - let packageName = moduleDirName; + let packageName: string | null = moduleDirName; // handle tree shaking - if (packageName.match('^_')) { + if (packageName && packageName.match('^_')) { // eslint-disable-next-line prefer-destructuring - packageName = packageName.match(/^_(@?[^@]+)/)[1]; + packageName = packageName.match(/^_(@?[^@]+)/)![1]; } return packageName; } -export default config => { +export default (config: any) => { // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 if ( process.env.ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site' || @@ -62,18 +62,19 @@ export default config => { minSize: 0, cacheGroups: { vendors: { - test: module => { + test: (module: { context: string }) => { const packageName = getModulePackageName(module); if (packageName) { return ['bizcharts', '@antv_data-set'].indexOf(packageName) >= 0; } return false; }, - name(module) { + name(module: { context: string }) { const packageName = getModulePackageName(module); - - if (['bizcharts', '@antv_data-set'].indexOf(packageName) >= 0) { - return 'viz'; // visualization package + if (packageName) { + if (['bizcharts', '@antv_data-set'].indexOf(packageName) >= 0) { + return 'viz'; // visualization package + } } return 'misc'; }, diff --git a/config/router.config.js b/config/router.config.js deleted file mode 100644 index cdff38e0b8..0000000000 --- a/config/router.config.js +++ /dev/null @@ -1,297 +0,0 @@ -export default [ - // user - { - path: '/user', - component: '../layouts/UserLayout', - routes: [ - { path: '/user', redirect: '/user/login' }, - { path: '/user/login', name: 'login', component: './User/Login' }, - { path: '/user/register', name: 'register', component: './User/Register' }, - { - path: '/user/register-result', - name: 'register.result', - component: './User/RegisterResult', - }, - { - component: '404', - }, - ], - }, - // app - { - path: '/', - component: '../layouts/BasicLayout', - Routes: ['src/pages/Authorized'], - routes: [ - // dashboard - { path: '/', redirect: '/dashboard/analysis', authority: ['admin', 'user'] }, - { - path: '/dashboard', - name: 'dashboard', - icon: 'dashboard', - routes: [ - { - path: '/dashboard/analysis', - name: 'analysis', - component: './Dashboard/Analysis', - }, - { - path: '/dashboard/monitor', - name: 'monitor', - component: './Dashboard/Monitor', - }, - { - path: '/dashboard/workplace', - name: 'workplace', - component: './Dashboard/Workplace', - }, - ], - }, - // forms - { - path: '/form', - icon: 'form', - name: 'form', - routes: [ - { - path: '/form/basic-form', - name: 'basicform', - component: './Forms/BasicForm', - }, - { - path: '/form/step-form', - name: 'stepform', - component: './Forms/StepForm', - hideChildrenInMenu: true, - routes: [ - { - path: '/form/step-form', - redirect: '/form/step-form/info', - }, - { - path: '/form/step-form/info', - name: 'info', - component: './Forms/StepForm/Step1', - }, - { - path: '/form/step-form/confirm', - name: 'confirm', - component: './Forms/StepForm/Step2', - }, - { - path: '/form/step-form/result', - name: 'result', - component: './Forms/StepForm/Step3', - }, - ], - }, - { - path: '/form/advanced-form', - name: 'advancedform', - authority: ['admin'], - component: './Forms/AdvancedForm', - }, - ], - }, - // list - { - path: '/list', - icon: 'table', - name: 'list', - routes: [ - { - path: '/list/table-list', - name: 'searchtable', - component: './List/TableList', - }, - { - path: '/list/basic-list', - name: 'basiclist', - component: './List/BasicList', - }, - { - path: '/list/card-list', - name: 'cardlist', - component: './List/CardList', - }, - { - path: '/list/search', - name: 'searchlist', - component: './List/List', - routes: [ - { - path: '/list/search', - redirect: '/list/search/articles', - }, - { - path: '/list/search/articles', - name: 'articles', - component: './List/Articles', - }, - { - path: '/list/search/projects', - name: 'projects', - component: './List/Projects', - }, - { - path: '/list/search/applications', - name: 'applications', - component: './List/Applications', - }, - ], - }, - ], - }, - { - path: '/profile', - name: 'profile', - icon: 'profile', - routes: [ - // profile - { - path: '/profile/basic', - name: 'basic', - component: './Profile/BasicProfile', - }, - { - path: '/profile/basic/:id', - hideInMenu: true, - component: './Profile/BasicProfile', - }, - { - path: '/profile/advanced', - name: 'advanced', - authority: ['admin'], - component: './Profile/AdvancedProfile', - }, - ], - }, - { - name: 'result', - icon: 'check-circle-o', - path: '/result', - routes: [ - // result - { - path: '/result/success', - name: 'success', - component: './Result/Success', - }, - { path: '/result/fail', name: 'fail', component: './Result/Error' }, - ], - }, - { - name: 'exception', - icon: 'warning', - path: '/exception', - routes: [ - // exception - { - path: '/exception/403', - name: 'not-permission', - component: './Exception/403', - }, - { - path: '/exception/404', - name: 'not-find', - component: './Exception/404', - }, - { - path: '/exception/500', - name: 'server-error', - component: './Exception/500', - }, - { - path: '/exception/trigger', - name: 'trigger', - hideInMenu: true, - component: './Exception/TriggerException', - }, - ], - }, - { - name: 'account', - icon: 'user', - path: '/account', - routes: [ - { - path: '/account/center', - name: 'center', - component: './Account/Center/Center', - routes: [ - { - path: '/account/center', - redirect: '/account/center/articles', - }, - { - path: '/account/center/articles', - component: './Account/Center/Articles', - }, - { - path: '/account/center/applications', - component: './Account/Center/Applications', - }, - { - path: '/account/center/projects', - component: './Account/Center/Projects', - }, - ], - }, - { - path: '/account/settings', - name: 'settings', - component: './Account/Settings/Info', - routes: [ - { - path: '/account/settings', - redirect: '/account/settings/base', - }, - { - path: '/account/settings/base', - component: './Account/Settings/BaseView', - }, - { - path: '/account/settings/security', - component: './Account/Settings/SecurityView', - }, - { - path: '/account/settings/binding', - component: './Account/Settings/BindingView', - }, - { - path: '/account/settings/notification', - component: './Account/Settings/NotificationView', - }, - ], - }, - ], - }, - // editor - { - name: 'editor', - icon: 'highlight', - path: '/editor', - routes: [ - { - path: '/editor/flow', - name: 'flow', - component: './Editor/GGEditor/Flow', - }, - { - path: '/editor/mind', - name: 'mind', - component: './Editor/GGEditor/Mind', - }, - { - path: '/editor/koni', - name: 'koni', - component: './Editor/GGEditor/Koni', - }, - ], - }, - { - component: '404', - }, - ], - }, -]; diff --git a/create-umi/README.md b/create-umi/README.md new file mode 100644 index 0000000000..14c3286ac4 --- /dev/null +++ b/create-umi/README.md @@ -0,0 +1,56 @@ +# Ant Design Pro + +This project is initialized with [Ant Design Pro](https://pro.ant.design). Follow is the quick guide for how to use. + +## Environment Prepare + +Install `node_modules`: +```bash +npm install +``` + +or + +```bash +yarn +``` + +## Provided Scripts + +Ant Design Pro provides some useful script to help you quick start and build with web project, code style check and test. + +Scripts provided in `package.json`. It's safe to modify or add additional script: + +### Start project + +```bash +npm start +``` + +### Build project + +```bash +npm run build +``` + +### Check code style + +```bash +npm run lint +``` + +You can also use script to auto fix some lint error: + +```bash +npm run lint:fix +``` + +### Test code + +```bash +npm test +``` + +## More + +You can view full document on our [official website](https://pro.ant.design). And welcome any feedback in our [github](https://github.com/ant-design/ant-design-pro). \ No newline at end of file diff --git a/create-umi/package.json b/create-umi/package.json new file mode 100644 index 0000000000..813bef862c --- /dev/null +++ b/create-umi/package.json @@ -0,0 +1,131 @@ +{ + "name": "ant-design-pro", + "version": "4.0.0", + "private": true, + "description": "An out-of-box UI solution for enterprise applications", + "scripts": { + "analyze": "cross-env ANALYZE=1 umi build", + "build": "umi build", + "generateMock": "node ./scripts/generateMock", + "lint": "npm run lint:js && npm run lint:ts && npm run lint:style && npm run lint:prettier", + "lint-staged": "lint-staged", + "lint-staged:js": "eslint --ext .js", + "lint-staged:ts": "tslint", + "lint:fix": "eslint --fix --ext .js src tests && npm run lint:style && npm run tslint:fix", + "lint:js": "eslint --ext .js src tests", + "lint:prettier": "check-prettier lint", + "lint:style": "stylelint --fix 'src/**/*.less' --syntax less", + "lint:ts": "tslint -p . -c tslint.yml", + "prettier": " check-prettier write", + "start": "umi dev", + "start:no-mock": "cross-env MOCK=none umi dev", + "test": "umi test", + "test:all": "node ./tests/run-tests.js", + "test:component": "umi test ./src/components", + "tslint:fix": "tslint --fix 'src/**/*.ts*'" + }, + "husky": { + "hooks": { + "pre-commit": "npm run lint-staged" + } + }, + "lint-staged": { + "**/*.less": "stylelint --syntax less", + "**/*.{js,jsx}": "npm run lint-staged:js", + "**/*.{js,ts,tsx,md,json,jsx,less}": [ "npm run prettier", "git add" ], + "**/*.{ts,tsx}": "npm run lint-staged:ts" + }, + "browserslist": [ "> 1%", "last 2 versions", "not ie <= 10" ], + "dependencies": { + "@ant-design/pro-layout": "^4.2.0", + "@antv/data-set": "^0.10.1", + "antd": "^3.16.1", + "bizcharts": "^3.5.3-beta.0", + "bizcharts-plugin-slider": "^2.1.1-beta.1", + "classnames": "^2.2.6", + "dva": "^2.4.0", + "lodash": "^4.17.10", + "lodash-decorators": "^6.0.0", + "memoize-one": "^5.0.0", + "moment": "^2.22.2", + "numeral": "^2.0.6", + "omit.js": "^1.0.0", + "path-to-regexp": "^2.4.0", + "qs": "^6.7.0", + "rc-animate": "^2.4.4", + "react": "^16.8.5", + "react-container-query": "^0.11.0", + "react-copy-to-clipboard": "^5.0.1", + "react-document-title": "^2.0.3", + "react-dom": "^16.7.0", + "react-fittext": "^1.0.0", + "react-media": "^1.9.2", + "react-media-hook2": "^1.0.2" + }, + "devDependencies": { + "@types/classnames": "^2.2.7", + "@types/history": "^4.7.2", + "@types/lodash": "^4.14.123", + "@types/react": "^16.8.1", + "@types/react-document-title": "^2.0.3", + "@types/react-dom": "^16.0.11", + "antd-pro-merge-less": "^1.0.0", + "antd-theme-webpack-plugin": "^1.2.0", + "babel-eslint": "^10.0.1", + "chalk": "^2.4.2", + "check-prettier": "^1.0.1", + "cross-env": "^5.2.0", + "cross-port-killer": "^1.0.1", + "enzyme": "^3.9.0", + "eslint": "^5.13.0", + "eslint-config-airbnb": "^17.1.0", + "eslint-config-prettier": "^4.1.0", + "eslint-plugin-babel": "^5.3.0", + "eslint-plugin-compat": "^2.6.3", + "eslint-plugin-import": "^2.16.0", + "eslint-plugin-jsx-a11y": "^6.2.1", + "eslint-plugin-markdown": "^1.0.0", + "eslint-plugin-react": "^7.12.4", + "express": "^4.16.4", + "gh-pages": "^2.0.1", + "husky": "^2.2.0", + "jest-puppeteer": "^4.1.0", + "jsdom-global": "^3.0.2", + "less": "^3.9.0", + "lint-staged": "^8.1.1", + "merge-umi-mock-data": "^1.0.4", + "mockjs": "^1.0.1-beta3", + "prettier": "^1.17.0", + "serverless-http": "^2.0.1", + "slash2": "^2.0.0", + "stylelint": "^9.10.1", + "stylelint-config-css-modules": "^1.3.0", + "stylelint-config-prettier": "^5.0.0", + "stylelint-config-rational-order": "^0.1.0", + "stylelint-config-standard": "^18.2.0", + "stylelint-declaration-block-no-ignored-properties": "^2.1.0", + "stylelint-order": "^2.0.0", + "tslint": "^5.12.1", + "tslint-config-prettier": "^1.17.0", + "tslint-eslint-rules": "^5.4.0", + "tslint-react": "^3.6.0", + "umi": "^2.7.0-beta.2", + "umi-plugin-ga": "^1.1.3", + "umi-plugin-pro-block": "^1.3.0", + "umi-plugin-react": "^1.8.0-beta.1", + "umi-request": "^1.0.0" + }, + "optionalDependencies": { + "puppeteer": "^1.12.1" + }, + "engines": { + "node": ">=10.0.0" + }, + "checkFiles": [ + "src/**/*.js*", + "src/**/*.ts*", + "src/**/*.less", + "config/**/*.js*", + "scripts/**/*.js" + ] +} diff --git a/jest-puppeteer.config.js b/jest-puppeteer.config.js index 2494ca09cc..21b41e4aaf 100644 --- a/jest-puppeteer.config.js +++ b/jest-puppeteer.config.js @@ -6,7 +6,7 @@ module.exports = { '--disable-dev-shm-usage', '--no-first-run', '--no-zygote', - '--no-sandbox' + '--no-sandbox', ], }, }; diff --git a/lambda/mock/index.js b/lambda/mock/index.js new file mode 100644 index 0000000000..3fec4b37bd --- /dev/null +++ b/lambda/mock/index.js @@ -0,0 +1,4199 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('mockjs'), require('moment')) : + typeof define === 'function' && define.amd ? define(['mockjs', 'moment'], factory) : + (global = global || self, global.mock = factory(global.mockjs, global.moment)); +}(this, function (mockjs, moment) { 'use strict'; + + mockjs = mockjs && mockjs.hasOwnProperty('default') ? mockjs['default'] : mockjs; + moment = moment && moment.hasOwnProperty('default') ? moment['default'] : moment; + + function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + + return obj; + } + + function _objectSpread(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i] != null ? arguments[i] : {}; + var ownKeys = Object.keys(source); + + if (typeof Object.getOwnPropertySymbols === 'function') { + ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { + return Object.getOwnPropertyDescriptor(source, sym).enumerable; + })); + } + + ownKeys.forEach(function (key) { + _defineProperty(target, key, source[key]); + }); + } + + return target; + } + + const titles = ['Alipay', 'Angular', 'Ant Design', 'Ant Design Pro', 'Bootstrap', 'React', 'Vue', 'Webpack']; + const avatars = ['https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png', // Alipay + 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png', // Angular + 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png', // Ant Design + 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png', // Ant Design Pro + 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png', // Bootstrap + 'https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png', // React + 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png', // Vue + 'https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png']; + const avatars2 = ['https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png', 'https://gw.alipayobjects.com/zos/rmsportal/cnrhVkzwxjPwAaCfPbdc.png', 'https://gw.alipayobjects.com/zos/rmsportal/gaOngJwsRYRaVAuXXcmB.png', 'https://gw.alipayobjects.com/zos/rmsportal/ubnKSIfAJTxIgXOKlciN.png', 'https://gw.alipayobjects.com/zos/rmsportal/WhxKECPNujWoWEFNdnJE.png', 'https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png', 'https://gw.alipayobjects.com/zos/rmsportal/psOgztMplJMGpVEqfcgF.png', 'https://gw.alipayobjects.com/zos/rmsportal/ZpBqSxLxVEXfcUNoPKrz.png', 'https://gw.alipayobjects.com/zos/rmsportal/laiEnJdGHVOhJrUShBaJ.png', 'https://gw.alipayobjects.com/zos/rmsportal/UrQsqscbKEpNuJcvBZBu.png']; + const covers = ['https://gw.alipayobjects.com/zos/rmsportal/uMfMFlvUuceEyPpotzlq.png', 'https://gw.alipayobjects.com/zos/rmsportal/iZBVOIhGJiAnhplqjvZW.png', 'https://gw.alipayobjects.com/zos/rmsportal/iXjVmWVHbCJAyqvDxdtx.png', 'https://gw.alipayobjects.com/zos/rmsportal/gLaIAoVWTtLbBWZNYEMg.png']; + const desc = ['那是一种内在的东西, 他们到达不了,也无法触及的', '希望是一个好东西,也许是最好的,好东西是不会消亡的', '生命就像一盒巧克力,结果往往出人意料', '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆', '那时候我只会想自己想要什么,从不想自己拥有什么']; + const user = ['付小小', '曲丽丽', '林东东', '周星星', '吴加好', '朱偏右', '鱼酱', '乐哥', '谭小仪', '仲尼']; + + function fakeList(count) { + const list = []; + + for (let i = 0; i < count; i += 1) { + list.push({ + id: `fake-list-${i}`, + owner: user[i % 10], + title: titles[i % 8], + avatar: avatars[i % 8], + cover: parseInt(i / 4, 10) % 2 === 0 ? covers[i % 4] : covers[3 - i % 4], + status: ['active', 'exception', 'normal'][i % 3], + percent: Math.ceil(Math.random() * 50) + 50, + logo: avatars[i % 8], + href: 'https://ant.design', + updatedAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 2 * i), + createdAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 2 * i), + subDescription: desc[i % 5], + description: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。', + activeUser: Math.ceil(Math.random() * 100000) + 100000, + newUser: Math.ceil(Math.random() * 1000) + 1000, + star: Math.ceil(Math.random() * 100) + 100, + like: Math.ceil(Math.random() * 100) + 100, + message: Math.ceil(Math.random() * 10) + 10, + content: '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。', + members: [{ + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png', + name: '曲丽丽', + id: 'member1' + }, { + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png', + name: '王昭君', + id: 'member2' + }, { + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png', + name: '董娜娜', + id: 'member3' + }] + }); + } + + return list; + } + + let sourceData; + + function getFakeList(req, res) { + const params = req.query; + const count = params.count * 1 || 20; + const result = fakeList(count); + sourceData = result; + return res.json(result); + } + + function postFakeList(req, res) { + const { + /* url = '', */ + body + } = req; // const params = getUrlParams(url); + + const { + method, + id + } = body; // const count = (params.count * 1) || 20; + + let result = sourceData; + + switch (method) { + case 'delete': + result = result.filter(item => item.id !== id); + break; + + case 'update': + result.forEach((item, i) => { + if (item.id === id) { + result[i] = Object.assign(item, body); + } + }); + break; + + case 'post': + result.unshift({ + body, + id: `fake-list-${result.length}`, + createdAt: new Date().getTime() + }); + break; + + default: + break; + } + + return res.json(result); + } + + const getNotice = [{ + id: 'xxx1', + title: titles[0], + logo: avatars[0], + description: '那是一种内在的东西,他们到达不了,也无法触及的', + updatedAt: new Date(), + member: '科学搬砖组', + href: '', + memberLink: '' + }, { + id: 'xxx2', + title: titles[1], + logo: avatars[1], + description: '希望是一个好东西,也许是最好的,好东西是不会消亡的', + updatedAt: new Date('2017-07-24'), + member: '全组都是吴彦祖', + href: '', + memberLink: '' + }, { + id: 'xxx3', + title: titles[2], + logo: avatars[2], + description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆', + updatedAt: new Date(), + member: '中二少女团', + href: '', + memberLink: '' + }, { + id: 'xxx4', + title: titles[3], + logo: avatars[3], + description: '那时候我只会想自己想要什么,从不想自己拥有什么', + updatedAt: new Date('2017-07-23'), + member: '程序员日常', + href: '', + memberLink: '' + }, { + id: 'xxx5', + title: titles[4], + logo: avatars[4], + description: '凛冬将至', + updatedAt: new Date('2017-07-23'), + member: '高逼格设计天团', + href: '', + memberLink: '' + }, { + id: 'xxx6', + title: titles[5], + logo: avatars[5], + description: '生命就像一盒巧克力,结果往往出人意料', + updatedAt: new Date('2017-07-23'), + member: '骗你来学计算机', + href: '', + memberLink: '' + }]; + const getActivities = [{ + id: 'trend-1', + updatedAt: new Date(), + user: { + name: '曲丽丽', + avatar: avatars2[0] + }, + group: { + name: '高逼格设计天团', + link: 'http://github.com/' + }, + project: { + name: '六月迭代', + link: 'http://github.com/' + }, + template: '在 @{group} 新建项目 @{project}' + }, { + id: 'trend-2', + updatedAt: new Date(), + user: { + name: '付小小', + avatar: avatars2[1] + }, + group: { + name: '高逼格设计天团', + link: 'http://github.com/' + }, + project: { + name: '六月迭代', + link: 'http://github.com/' + }, + template: '在 @{group} 新建项目 @{project}' + }, { + id: 'trend-3', + updatedAt: new Date(), + user: { + name: '林东东', + avatar: avatars2[2] + }, + group: { + name: '中二少女团', + link: 'http://github.com/' + }, + project: { + name: '六月迭代', + link: 'http://github.com/' + }, + template: '在 @{group} 新建项目 @{project}' + }, { + id: 'trend-4', + updatedAt: new Date(), + user: { + name: '周星星', + avatar: avatars2[4] + }, + project: { + name: '5 月日常迭代', + link: 'http://github.com/' + }, + template: '将 @{project} 更新至已发布状态' + }, { + id: 'trend-5', + updatedAt: new Date(), + user: { + name: '朱偏右', + avatar: avatars2[3] + }, + project: { + name: '工程效能', + link: 'http://github.com/' + }, + comment: { + name: '留言', + link: 'http://github.com/' + }, + template: '在 @{project} 发布了 @{comment}' + }, { + id: 'trend-6', + updatedAt: new Date(), + user: { + name: '乐哥', + avatar: avatars2[5] + }, + group: { + name: '程序员日常', + link: 'http://github.com/' + }, + project: { + name: '品牌迭代', + link: 'http://github.com/' + }, + template: '在 @{group} 新建项目 @{project}' + }]; + + function getFakeCaptcha(req, res) { + return res.json('captcha-xxx'); + } + + var api = { + 'GET /api/project/notice': getNotice, + 'GET /api/activities': getActivities, + 'POST /api/forms': (req, res) => { + res.send({ + message: 'Ok' + }); + }, + 'GET /api/tags': mockjs.mock({ + 'list|100': [{ + name: '@city', + 'value|1-100': 150, + 'type|0-2': 1 + }] + }), + 'GET /api/fake_list': getFakeList, + 'POST /api/fake_list': postFakeList, + 'GET /api/captcha': getFakeCaptcha + }; + + const visitData = []; + const beginDay = new Date().getTime(); + const fakeY = [7, 5, 4, 2, 4, 7, 5, 6, 5, 9, 6, 3, 1, 5, 3, 6, 5]; + + for (let i = 0; i < fakeY.length; i += 1) { + visitData.push({ + x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'), + y: fakeY[i] + }); + } + + const visitData2 = []; + const fakeY2 = [1, 6, 4, 8, 3, 7, 2]; + + for (let i = 0; i < fakeY2.length; i += 1) { + visitData2.push({ + x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'), + y: fakeY2[i] + }); + } + + const salesData = []; + + for (let i = 0; i < 12; i += 1) { + salesData.push({ + x: `${i + 1}月`, + y: Math.floor(Math.random() * 1000) + 200 + }); + } + + const searchData = []; + + for (let i = 0; i < 50; i += 1) { + searchData.push({ + index: i + 1, + keyword: `搜索关键词-${i}`, + count: Math.floor(Math.random() * 1000), + range: Math.floor(Math.random() * 100), + status: Math.floor(Math.random() * 10 % 2) + }); + } + + const salesTypeData = [{ + x: '家用电器', + y: 4544 + }, { + x: '食用酒水', + y: 3321 + }, { + x: '个护健康', + y: 3113 + }, { + x: '服饰箱包', + y: 2341 + }, { + x: '母婴产品', + y: 1231 + }, { + x: '其他', + y: 1231 + }]; + const salesTypeDataOnline = [{ + x: '家用电器', + y: 244 + }, { + x: '食用酒水', + y: 321 + }, { + x: '个护健康', + y: 311 + }, { + x: '服饰箱包', + y: 41 + }, { + x: '母婴产品', + y: 121 + }, { + x: '其他', + y: 111 + }]; + const salesTypeDataOffline = [{ + x: '家用电器', + y: 99 + }, { + x: '食用酒水', + y: 188 + }, { + x: '个护健康', + y: 344 + }, { + x: '服饰箱包', + y: 255 + }, { + x: '其他', + y: 65 + }]; + const offlineData = []; + + for (let i = 0; i < 10; i += 1) { + offlineData.push({ + name: `Stores ${i}`, + cvr: Math.ceil(Math.random() * 9) / 10 + }); + } + + const offlineChartData = []; + + for (let i = 0; i < 20; i += 1) { + offlineChartData.push({ + x: new Date().getTime() + 1000 * 60 * 30 * i, + y1: Math.floor(Math.random() * 100) + 10, + y2: Math.floor(Math.random() * 100) + 10 + }); + } + + const radarOriginData = [{ + name: '个人', + ref: 10, + koubei: 8, + output: 4, + contribute: 5, + hot: 7 + }, { + name: '团队', + ref: 3, + koubei: 9, + output: 6, + contribute: 3, + hot: 1 + }, { + name: '部门', + ref: 4, + koubei: 1, + output: 6, + contribute: 5, + hot: 7 + }]; + const radarData = []; + const radarTitleMap = { + ref: '引用', + koubei: '口碑', + output: '产量', + contribute: '贡献', + hot: '热度' + }; + radarOriginData.forEach(item => { + Object.keys(item).forEach(key => { + if (key !== 'name') { + radarData.push({ + name: item.name, + label: radarTitleMap[key], + value: item[key] + }); + } + }); + }); + const getFakeChartData = { + visitData, + visitData2, + salesData, + searchData, + offlineData, + offlineChartData, + salesTypeData, + salesTypeDataOnline, + salesTypeDataOffline, + radarData + }; + var chart = { + 'GET /api/fake_chart_data': getFakeChartData + }; + + var city = { + "110000": [ + { + province: "北京市", + name: "市辖区", + id: "110100" + } + ], + "120000": [ + { + province: "天津市", + name: "市辖区", + id: "120100" + } + ], + "130000": [ + { + province: "河北省", + name: "石家庄市", + id: "130100" + }, + { + province: "河北省", + name: "唐山市", + id: "130200" + }, + { + province: "河北省", + name: "秦皇岛市", + id: "130300" + }, + { + province: "河北省", + name: "邯郸市", + id: "130400" + }, + { + province: "河北省", + name: "邢台市", + id: "130500" + }, + { + province: "河北省", + name: "保定市", + id: "130600" + }, + { + province: "河北省", + name: "张家口市", + id: "130700" + }, + { + province: "河北省", + name: "承德市", + id: "130800" + }, + { + province: "河北省", + name: "沧州市", + id: "130900" + }, + { + province: "河北省", + name: "廊坊市", + id: "131000" + }, + { + province: "河北省", + name: "衡水市", + id: "131100" + }, + { + province: "河北省", + name: "省直辖县级行政区划", + id: "139000" + } + ], + "140000": [ + { + province: "山西省", + name: "太原市", + id: "140100" + }, + { + province: "山西省", + name: "大同市", + id: "140200" + }, + { + province: "山西省", + name: "阳泉市", + id: "140300" + }, + { + province: "山西省", + name: "长治市", + id: "140400" + }, + { + province: "山西省", + name: "晋城市", + id: "140500" + }, + { + province: "山西省", + name: "朔州市", + id: "140600" + }, + { + province: "山西省", + name: "晋中市", + id: "140700" + }, + { + province: "山西省", + name: "运城市", + id: "140800" + }, + { + province: "山西省", + name: "忻州市", + id: "140900" + }, + { + province: "山西省", + name: "临汾市", + id: "141000" + }, + { + province: "山西省", + name: "吕梁市", + id: "141100" + } + ], + "150000": [ + { + province: "内蒙古自治区", + name: "呼和浩特市", + id: "150100" + }, + { + province: "内蒙古自治区", + name: "包头市", + id: "150200" + }, + { + province: "内蒙古自治区", + name: "乌海市", + id: "150300" + }, + { + province: "内蒙古自治区", + name: "赤峰市", + id: "150400" + }, + { + province: "内蒙古自治区", + name: "通辽市", + id: "150500" + }, + { + province: "内蒙古自治区", + name: "鄂尔多斯市", + id: "150600" + }, + { + province: "内蒙古自治区", + name: "呼伦贝尔市", + id: "150700" + }, + { + province: "内蒙古自治区", + name: "巴彦淖尔市", + id: "150800" + }, + { + province: "内蒙古自治区", + name: "乌兰察布市", + id: "150900" + }, + { + province: "内蒙古自治区", + name: "兴安盟", + id: "152200" + }, + { + province: "内蒙古自治区", + name: "锡林郭勒盟", + id: "152500" + }, + { + province: "内蒙古自治区", + name: "阿拉善盟", + id: "152900" + } + ], + "210000": [ + { + province: "辽宁省", + name: "沈阳市", + id: "210100" + }, + { + province: "辽宁省", + name: "大连市", + id: "210200" + }, + { + province: "辽宁省", + name: "鞍山市", + id: "210300" + }, + { + province: "辽宁省", + name: "抚顺市", + id: "210400" + }, + { + province: "辽宁省", + name: "本溪市", + id: "210500" + }, + { + province: "辽宁省", + name: "丹东市", + id: "210600" + }, + { + province: "辽宁省", + name: "锦州市", + id: "210700" + }, + { + province: "辽宁省", + name: "营口市", + id: "210800" + }, + { + province: "辽宁省", + name: "阜新市", + id: "210900" + }, + { + province: "辽宁省", + name: "辽阳市", + id: "211000" + }, + { + province: "辽宁省", + name: "盘锦市", + id: "211100" + }, + { + province: "辽宁省", + name: "铁岭市", + id: "211200" + }, + { + province: "辽宁省", + name: "朝阳市", + id: "211300" + }, + { + province: "辽宁省", + name: "葫芦岛市", + id: "211400" + } + ], + "220000": [ + { + province: "吉林省", + name: "长春市", + id: "220100" + }, + { + province: "吉林省", + name: "吉林市", + id: "220200" + }, + { + province: "吉林省", + name: "四平市", + id: "220300" + }, + { + province: "吉林省", + name: "辽源市", + id: "220400" + }, + { + province: "吉林省", + name: "通化市", + id: "220500" + }, + { + province: "吉林省", + name: "白山市", + id: "220600" + }, + { + province: "吉林省", + name: "松原市", + id: "220700" + }, + { + province: "吉林省", + name: "白城市", + id: "220800" + }, + { + province: "吉林省", + name: "延边朝鲜族自治州", + id: "222400" + } + ], + "230000": [ + { + province: "黑龙江省", + name: "哈尔滨市", + id: "230100" + }, + { + province: "黑龙江省", + name: "齐齐哈尔市", + id: "230200" + }, + { + province: "黑龙江省", + name: "鸡西市", + id: "230300" + }, + { + province: "黑龙江省", + name: "鹤岗市", + id: "230400" + }, + { + province: "黑龙江省", + name: "双鸭山市", + id: "230500" + }, + { + province: "黑龙江省", + name: "大庆市", + id: "230600" + }, + { + province: "黑龙江省", + name: "伊春市", + id: "230700" + }, + { + province: "黑龙江省", + name: "佳木斯市", + id: "230800" + }, + { + province: "黑龙江省", + name: "七台河市", + id: "230900" + }, + { + province: "黑龙江省", + name: "牡丹江市", + id: "231000" + }, + { + province: "黑龙江省", + name: "黑河市", + id: "231100" + }, + { + province: "黑龙江省", + name: "绥化市", + id: "231200" + }, + { + province: "黑龙江省", + name: "大兴安岭地区", + id: "232700" + } + ], + "310000": [ + { + province: "上海市", + name: "市辖区", + id: "310100" + } + ], + "320000": [ + { + province: "江苏省", + name: "南京市", + id: "320100" + }, + { + province: "江苏省", + name: "无锡市", + id: "320200" + }, + { + province: "江苏省", + name: "徐州市", + id: "320300" + }, + { + province: "江苏省", + name: "常州市", + id: "320400" + }, + { + province: "江苏省", + name: "苏州市", + id: "320500" + }, + { + province: "江苏省", + name: "南通市", + id: "320600" + }, + { + province: "江苏省", + name: "连云港市", + id: "320700" + }, + { + province: "江苏省", + name: "淮安市", + id: "320800" + }, + { + province: "江苏省", + name: "盐城市", + id: "320900" + }, + { + province: "江苏省", + name: "扬州市", + id: "321000" + }, + { + province: "江苏省", + name: "镇江市", + id: "321100" + }, + { + province: "江苏省", + name: "泰州市", + id: "321200" + }, + { + province: "江苏省", + name: "宿迁市", + id: "321300" + } + ], + "330000": [ + { + province: "浙江省", + name: "杭州市", + id: "330100" + }, + { + province: "浙江省", + name: "宁波市", + id: "330200" + }, + { + province: "浙江省", + name: "温州市", + id: "330300" + }, + { + province: "浙江省", + name: "嘉兴市", + id: "330400" + }, + { + province: "浙江省", + name: "湖州市", + id: "330500" + }, + { + province: "浙江省", + name: "绍兴市", + id: "330600" + }, + { + province: "浙江省", + name: "金华市", + id: "330700" + }, + { + province: "浙江省", + name: "衢州市", + id: "330800" + }, + { + province: "浙江省", + name: "舟山市", + id: "330900" + }, + { + province: "浙江省", + name: "台州市", + id: "331000" + }, + { + province: "浙江省", + name: "丽水市", + id: "331100" + } + ], + "340000": [ + { + province: "安徽省", + name: "合肥市", + id: "340100" + }, + { + province: "安徽省", + name: "芜湖市", + id: "340200" + }, + { + province: "安徽省", + name: "蚌埠市", + id: "340300" + }, + { + province: "安徽省", + name: "淮南市", + id: "340400" + }, + { + province: "安徽省", + name: "马鞍山市", + id: "340500" + }, + { + province: "安徽省", + name: "淮北市", + id: "340600" + }, + { + province: "安徽省", + name: "铜陵市", + id: "340700" + }, + { + province: "安徽省", + name: "安庆市", + id: "340800" + }, + { + province: "安徽省", + name: "黄山市", + id: "341000" + }, + { + province: "安徽省", + name: "滁州市", + id: "341100" + }, + { + province: "安徽省", + name: "阜阳市", + id: "341200" + }, + { + province: "安徽省", + name: "宿州市", + id: "341300" + }, + { + province: "安徽省", + name: "六安市", + id: "341500" + }, + { + province: "安徽省", + name: "亳州市", + id: "341600" + }, + { + province: "安徽省", + name: "池州市", + id: "341700" + }, + { + province: "安徽省", + name: "宣城市", + id: "341800" + } + ], + "350000": [ + { + province: "福建省", + name: "福州市", + id: "350100" + }, + { + province: "福建省", + name: "厦门市", + id: "350200" + }, + { + province: "福建省", + name: "莆田市", + id: "350300" + }, + { + province: "福建省", + name: "三明市", + id: "350400" + }, + { + province: "福建省", + name: "泉州市", + id: "350500" + }, + { + province: "福建省", + name: "漳州市", + id: "350600" + }, + { + province: "福建省", + name: "南平市", + id: "350700" + }, + { + province: "福建省", + name: "龙岩市", + id: "350800" + }, + { + province: "福建省", + name: "宁德市", + id: "350900" + } + ], + "360000": [ + { + province: "江西省", + name: "南昌市", + id: "360100" + }, + { + province: "江西省", + name: "景德镇市", + id: "360200" + }, + { + province: "江西省", + name: "萍乡市", + id: "360300" + }, + { + province: "江西省", + name: "九江市", + id: "360400" + }, + { + province: "江西省", + name: "新余市", + id: "360500" + }, + { + province: "江西省", + name: "鹰潭市", + id: "360600" + }, + { + province: "江西省", + name: "赣州市", + id: "360700" + }, + { + province: "江西省", + name: "吉安市", + id: "360800" + }, + { + province: "江西省", + name: "宜春市", + id: "360900" + }, + { + province: "江西省", + name: "抚州市", + id: "361000" + }, + { + province: "江西省", + name: "上饶市", + id: "361100" + } + ], + "370000": [ + { + province: "山东省", + name: "济南市", + id: "370100" + }, + { + province: "山东省", + name: "青岛市", + id: "370200" + }, + { + province: "山东省", + name: "淄博市", + id: "370300" + }, + { + province: "山东省", + name: "枣庄市", + id: "370400" + }, + { + province: "山东省", + name: "东营市", + id: "370500" + }, + { + province: "山东省", + name: "烟台市", + id: "370600" + }, + { + province: "山东省", + name: "潍坊市", + id: "370700" + }, + { + province: "山东省", + name: "济宁市", + id: "370800" + }, + { + province: "山东省", + name: "泰安市", + id: "370900" + }, + { + province: "山东省", + name: "威海市", + id: "371000" + }, + { + province: "山东省", + name: "日照市", + id: "371100" + }, + { + province: "山东省", + name: "莱芜市", + id: "371200" + }, + { + province: "山东省", + name: "临沂市", + id: "371300" + }, + { + province: "山东省", + name: "德州市", + id: "371400" + }, + { + province: "山东省", + name: "聊城市", + id: "371500" + }, + { + province: "山东省", + name: "滨州市", + id: "371600" + }, + { + province: "山东省", + name: "菏泽市", + id: "371700" + } + ], + "410000": [ + { + province: "河南省", + name: "郑州市", + id: "410100" + }, + { + province: "河南省", + name: "开封市", + id: "410200" + }, + { + province: "河南省", + name: "洛阳市", + id: "410300" + }, + { + province: "河南省", + name: "平顶山市", + id: "410400" + }, + { + province: "河南省", + name: "安阳市", + id: "410500" + }, + { + province: "河南省", + name: "鹤壁市", + id: "410600" + }, + { + province: "河南省", + name: "新乡市", + id: "410700" + }, + { + province: "河南省", + name: "焦作市", + id: "410800" + }, + { + province: "河南省", + name: "濮阳市", + id: "410900" + }, + { + province: "河南省", + name: "许昌市", + id: "411000" + }, + { + province: "河南省", + name: "漯河市", + id: "411100" + }, + { + province: "河南省", + name: "三门峡市", + id: "411200" + }, + { + province: "河南省", + name: "南阳市", + id: "411300" + }, + { + province: "河南省", + name: "商丘市", + id: "411400" + }, + { + province: "河南省", + name: "信阳市", + id: "411500" + }, + { + province: "河南省", + name: "周口市", + id: "411600" + }, + { + province: "河南省", + name: "驻马店市", + id: "411700" + }, + { + province: "河南省", + name: "省直辖县级行政区划", + id: "419000" + } + ], + "420000": [ + { + province: "湖北省", + name: "武汉市", + id: "420100" + }, + { + province: "湖北省", + name: "黄石市", + id: "420200" + }, + { + province: "湖北省", + name: "十堰市", + id: "420300" + }, + { + province: "湖北省", + name: "宜昌市", + id: "420500" + }, + { + province: "湖北省", + name: "襄阳市", + id: "420600" + }, + { + province: "湖北省", + name: "鄂州市", + id: "420700" + }, + { + province: "湖北省", + name: "荆门市", + id: "420800" + }, + { + province: "湖北省", + name: "孝感市", + id: "420900" + }, + { + province: "湖北省", + name: "荆州市", + id: "421000" + }, + { + province: "湖北省", + name: "黄冈市", + id: "421100" + }, + { + province: "湖北省", + name: "咸宁市", + id: "421200" + }, + { + province: "湖北省", + name: "随州市", + id: "421300" + }, + { + province: "湖北省", + name: "恩施土家族苗族自治州", + id: "422800" + }, + { + province: "湖北省", + name: "省直辖县级行政区划", + id: "429000" + } + ], + "430000": [ + { + province: "湖南省", + name: "长沙市", + id: "430100" + }, + { + province: "湖南省", + name: "株洲市", + id: "430200" + }, + { + province: "湖南省", + name: "湘潭市", + id: "430300" + }, + { + province: "湖南省", + name: "衡阳市", + id: "430400" + }, + { + province: "湖南省", + name: "邵阳市", + id: "430500" + }, + { + province: "湖南省", + name: "岳阳市", + id: "430600" + }, + { + province: "湖南省", + name: "常德市", + id: "430700" + }, + { + province: "湖南省", + name: "张家界市", + id: "430800" + }, + { + province: "湖南省", + name: "益阳市", + id: "430900" + }, + { + province: "湖南省", + name: "郴州市", + id: "431000" + }, + { + province: "湖南省", + name: "永州市", + id: "431100" + }, + { + province: "湖南省", + name: "怀化市", + id: "431200" + }, + { + province: "湖南省", + name: "娄底市", + id: "431300" + }, + { + province: "湖南省", + name: "湘西土家族苗族自治州", + id: "433100" + } + ], + "440000": [ + { + province: "广东省", + name: "广州市", + id: "440100" + }, + { + province: "广东省", + name: "韶关市", + id: "440200" + }, + { + province: "广东省", + name: "深圳市", + id: "440300" + }, + { + province: "广东省", + name: "珠海市", + id: "440400" + }, + { + province: "广东省", + name: "汕头市", + id: "440500" + }, + { + province: "广东省", + name: "佛山市", + id: "440600" + }, + { + province: "广东省", + name: "江门市", + id: "440700" + }, + { + province: "广东省", + name: "湛江市", + id: "440800" + }, + { + province: "广东省", + name: "茂名市", + id: "440900" + }, + { + province: "广东省", + name: "肇庆市", + id: "441200" + }, + { + province: "广东省", + name: "惠州市", + id: "441300" + }, + { + province: "广东省", + name: "梅州市", + id: "441400" + }, + { + province: "广东省", + name: "汕尾市", + id: "441500" + }, + { + province: "广东省", + name: "河源市", + id: "441600" + }, + { + province: "广东省", + name: "阳江市", + id: "441700" + }, + { + province: "广东省", + name: "清远市", + id: "441800" + }, + { + province: "广东省", + name: "东莞市", + id: "441900" + }, + { + province: "广东省", + name: "中山市", + id: "442000" + }, + { + province: "广东省", + name: "潮州市", + id: "445100" + }, + { + province: "广东省", + name: "揭阳市", + id: "445200" + }, + { + province: "广东省", + name: "云浮市", + id: "445300" + } + ], + "450000": [ + { + province: "广西壮族自治区", + name: "南宁市", + id: "450100" + }, + { + province: "广西壮族自治区", + name: "柳州市", + id: "450200" + }, + { + province: "广西壮族自治区", + name: "桂林市", + id: "450300" + }, + { + province: "广西壮族自治区", + name: "梧州市", + id: "450400" + }, + { + province: "广西壮族自治区", + name: "北海市", + id: "450500" + }, + { + province: "广西壮族自治区", + name: "防城港市", + id: "450600" + }, + { + province: "广西壮族自治区", + name: "钦州市", + id: "450700" + }, + { + province: "广西壮族自治区", + name: "贵港市", + id: "450800" + }, + { + province: "广西壮族自治区", + name: "玉林市", + id: "450900" + }, + { + province: "广西壮族自治区", + name: "百色市", + id: "451000" + }, + { + province: "广西壮族自治区", + name: "贺州市", + id: "451100" + }, + { + province: "广西壮族自治区", + name: "河池市", + id: "451200" + }, + { + province: "广西壮族自治区", + name: "来宾市", + id: "451300" + }, + { + province: "广西壮族自治区", + name: "崇左市", + id: "451400" + } + ], + "460000": [ + { + province: "海南省", + name: "海口市", + id: "460100" + }, + { + province: "海南省", + name: "三亚市", + id: "460200" + }, + { + province: "海南省", + name: "三沙市", + id: "460300" + }, + { + province: "海南省", + name: "儋州市", + id: "460400" + }, + { + province: "海南省", + name: "省直辖县级行政区划", + id: "469000" + } + ], + "500000": [ + { + province: "重庆市", + name: "市辖区", + id: "500100" + }, + { + province: "重庆市", + name: "县", + id: "500200" + } + ], + "510000": [ + { + province: "四川省", + name: "成都市", + id: "510100" + }, + { + province: "四川省", + name: "自贡市", + id: "510300" + }, + { + province: "四川省", + name: "攀枝花市", + id: "510400" + }, + { + province: "四川省", + name: "泸州市", + id: "510500" + }, + { + province: "四川省", + name: "德阳市", + id: "510600" + }, + { + province: "四川省", + name: "绵阳市", + id: "510700" + }, + { + province: "四川省", + name: "广元市", + id: "510800" + }, + { + province: "四川省", + name: "遂宁市", + id: "510900" + }, + { + province: "四川省", + name: "内江市", + id: "511000" + }, + { + province: "四川省", + name: "乐山市", + id: "511100" + }, + { + province: "四川省", + name: "南充市", + id: "511300" + }, + { + province: "四川省", + name: "眉山市", + id: "511400" + }, + { + province: "四川省", + name: "宜宾市", + id: "511500" + }, + { + province: "四川省", + name: "广安市", + id: "511600" + }, + { + province: "四川省", + name: "达州市", + id: "511700" + }, + { + province: "四川省", + name: "雅安市", + id: "511800" + }, + { + province: "四川省", + name: "巴中市", + id: "511900" + }, + { + province: "四川省", + name: "资阳市", + id: "512000" + }, + { + province: "四川省", + name: "阿坝藏族羌族自治州", + id: "513200" + }, + { + province: "四川省", + name: "甘孜藏族自治州", + id: "513300" + }, + { + province: "四川省", + name: "凉山彝族自治州", + id: "513400" + } + ], + "520000": [ + { + province: "贵州省", + name: "贵阳市", + id: "520100" + }, + { + province: "贵州省", + name: "六盘水市", + id: "520200" + }, + { + province: "贵州省", + name: "遵义市", + id: "520300" + }, + { + province: "贵州省", + name: "安顺市", + id: "520400" + }, + { + province: "贵州省", + name: "毕节市", + id: "520500" + }, + { + province: "贵州省", + name: "铜仁市", + id: "520600" + }, + { + province: "贵州省", + name: "黔西南布依族苗族自治州", + id: "522300" + }, + { + province: "贵州省", + name: "黔东南苗族侗族自治州", + id: "522600" + }, + { + province: "贵州省", + name: "黔南布依族苗族自治州", + id: "522700" + } + ], + "530000": [ + { + province: "云南省", + name: "昆明市", + id: "530100" + }, + { + province: "云南省", + name: "曲靖市", + id: "530300" + }, + { + province: "云南省", + name: "玉溪市", + id: "530400" + }, + { + province: "云南省", + name: "保山市", + id: "530500" + }, + { + province: "云南省", + name: "昭通市", + id: "530600" + }, + { + province: "云南省", + name: "丽江市", + id: "530700" + }, + { + province: "云南省", + name: "普洱市", + id: "530800" + }, + { + province: "云南省", + name: "临沧市", + id: "530900" + }, + { + province: "云南省", + name: "楚雄彝族自治州", + id: "532300" + }, + { + province: "云南省", + name: "红河哈尼族彝族自治州", + id: "532500" + }, + { + province: "云南省", + name: "文山壮族苗族自治州", + id: "532600" + }, + { + province: "云南省", + name: "西双版纳傣族自治州", + id: "532800" + }, + { + province: "云南省", + name: "大理白族自治州", + id: "532900" + }, + { + province: "云南省", + name: "德宏傣族景颇族自治州", + id: "533100" + }, + { + province: "云南省", + name: "怒江傈僳族自治州", + id: "533300" + }, + { + province: "云南省", + name: "迪庆藏族自治州", + id: "533400" + } + ], + "540000": [ + { + province: "西藏自治区", + name: "拉萨市", + id: "540100" + }, + { + province: "西藏自治区", + name: "日喀则市", + id: "540200" + }, + { + province: "西藏自治区", + name: "昌都市", + id: "540300" + }, + { + province: "西藏自治区", + name: "林芝市", + id: "540400" + }, + { + province: "西藏自治区", + name: "山南市", + id: "540500" + }, + { + province: "西藏自治区", + name: "那曲地区", + id: "542400" + }, + { + province: "西藏自治区", + name: "阿里地区", + id: "542500" + } + ], + "610000": [ + { + province: "陕西省", + name: "西安市", + id: "610100" + }, + { + province: "陕西省", + name: "铜川市", + id: "610200" + }, + { + province: "陕西省", + name: "宝鸡市", + id: "610300" + }, + { + province: "陕西省", + name: "咸阳市", + id: "610400" + }, + { + province: "陕西省", + name: "渭南市", + id: "610500" + }, + { + province: "陕西省", + name: "延安市", + id: "610600" + }, + { + province: "陕西省", + name: "汉中市", + id: "610700" + }, + { + province: "陕西省", + name: "榆林市", + id: "610800" + }, + { + province: "陕西省", + name: "安康市", + id: "610900" + }, + { + province: "陕西省", + name: "商洛市", + id: "611000" + } + ], + "620000": [ + { + province: "甘肃省", + name: "兰州市", + id: "620100" + }, + { + province: "甘肃省", + name: "嘉峪关市", + id: "620200" + }, + { + province: "甘肃省", + name: "金昌市", + id: "620300" + }, + { + province: "甘肃省", + name: "白银市", + id: "620400" + }, + { + province: "甘肃省", + name: "天水市", + id: "620500" + }, + { + province: "甘肃省", + name: "武威市", + id: "620600" + }, + { + province: "甘肃省", + name: "张掖市", + id: "620700" + }, + { + province: "甘肃省", + name: "平凉市", + id: "620800" + }, + { + province: "甘肃省", + name: "酒泉市", + id: "620900" + }, + { + province: "甘肃省", + name: "庆阳市", + id: "621000" + }, + { + province: "甘肃省", + name: "定西市", + id: "621100" + }, + { + province: "甘肃省", + name: "陇南市", + id: "621200" + }, + { + province: "甘肃省", + name: "临夏回族自治州", + id: "622900" + }, + { + province: "甘肃省", + name: "甘南藏族自治州", + id: "623000" + } + ], + "630000": [ + { + province: "青海省", + name: "西宁市", + id: "630100" + }, + { + province: "青海省", + name: "海东市", + id: "630200" + }, + { + province: "青海省", + name: "海北藏族自治州", + id: "632200" + }, + { + province: "青海省", + name: "黄南藏族自治州", + id: "632300" + }, + { + province: "青海省", + name: "海南藏族自治州", + id: "632500" + }, + { + province: "青海省", + name: "果洛藏族自治州", + id: "632600" + }, + { + province: "青海省", + name: "玉树藏族自治州", + id: "632700" + }, + { + province: "青海省", + name: "海西蒙古族藏族自治州", + id: "632800" + } + ], + "640000": [ + { + province: "宁夏回族自治区", + name: "银川市", + id: "640100" + }, + { + province: "宁夏回族自治区", + name: "石嘴山市", + id: "640200" + }, + { + province: "宁夏回族自治区", + name: "吴忠市", + id: "640300" + }, + { + province: "宁夏回族自治区", + name: "固原市", + id: "640400" + }, + { + province: "宁夏回族自治区", + name: "中卫市", + id: "640500" + } + ], + "650000": [ + { + province: "新疆维吾尔自治区", + name: "乌鲁木齐市", + id: "650100" + }, + { + province: "新疆维吾尔自治区", + name: "克拉玛依市", + id: "650200" + }, + { + province: "新疆维吾尔自治区", + name: "吐鲁番市", + id: "650400" + }, + { + province: "新疆维吾尔自治区", + name: "哈密市", + id: "650500" + }, + { + province: "新疆维吾尔自治区", + name: "昌吉回族自治州", + id: "652300" + }, + { + province: "新疆维吾尔自治区", + name: "博尔塔拉蒙古自治州", + id: "652700" + }, + { + province: "新疆维吾尔自治区", + name: "巴音郭楞蒙古自治州", + id: "652800" + }, + { + province: "新疆维吾尔自治区", + name: "阿克苏地区", + id: "652900" + }, + { + province: "新疆维吾尔自治区", + name: "克孜勒苏柯尔克孜自治州", + id: "653000" + }, + { + province: "新疆维吾尔自治区", + name: "喀什地区", + id: "653100" + }, + { + province: "新疆维吾尔自治区", + name: "和田地区", + id: "653200" + }, + { + province: "新疆维吾尔自治区", + name: "伊犁哈萨克自治州", + id: "654000" + }, + { + province: "新疆维吾尔自治区", + name: "塔城地区", + id: "654200" + }, + { + province: "新疆维吾尔自治区", + name: "阿勒泰地区", + id: "654300" + }, + { + province: "新疆维吾尔自治区", + name: "自治区直辖县级行政区划", + id: "659000" + } + ] + }; + + var province = [ + { + "name": "北京市", + "id": "110000" + }, + { + "name": "天津市", + "id": "120000" + }, + { + "name": "河北省", + "id": "130000" + }, + { + "name": "山西省", + "id": "140000" + }, + { + "name": "内蒙古自治区", + "id": "150000" + }, + { + "name": "辽宁省", + "id": "210000" + }, + { + "name": "吉林省", + "id": "220000" + }, + { + "name": "黑龙江省", + "id": "230000" + }, + { + "name": "上海市", + "id": "310000" + }, + { + "name": "江苏省", + "id": "320000" + }, + { + "name": "浙江省", + "id": "330000" + }, + { + "name": "安徽省", + "id": "340000" + }, + { + "name": "福建省", + "id": "350000" + }, + { + "name": "江西省", + "id": "360000" + }, + { + "name": "山东省", + "id": "370000" + }, + { + "name": "河南省", + "id": "410000" + }, + { + "name": "湖北省", + "id": "420000" + }, + { + "name": "湖南省", + "id": "430000" + }, + { + "name": "广东省", + "id": "440000" + }, + { + "name": "广西壮族自治区", + "id": "450000" + }, + { + "name": "海南省", + "id": "460000" + }, + { + "name": "重庆市", + "id": "500000" + }, + { + "name": "四川省", + "id": "510000" + }, + { + "name": "贵州省", + "id": "520000" + }, + { + "name": "云南省", + "id": "530000" + }, + { + "name": "西藏自治区", + "id": "540000" + }, + { + "name": "陕西省", + "id": "610000" + }, + { + "name": "甘肃省", + "id": "620000" + }, + { + "name": "青海省", + "id": "630000" + }, + { + "name": "宁夏回族自治区", + "id": "640000" + }, + { + "name": "新疆维吾尔自治区", + "id": "650000" + }, + { + "name": "台湾省", + "id": "710000" + }, + { + "name": "香港特别行政区", + "id": "810000" + }, + { + "name": "澳门特别行政区", + "id": "820000" + } + ] + ; + + function getProvince(req, res) { + return res.json(province); + } + + function getCity(req, res) { + return res.json(city[req.params.province]); + } + + var geographic = { + 'GET /api/geographic/province': getProvince, + 'GET /api/geographic/city/:province': getCity + }; + + const getNotices = (req, res) => res.json([{ + id: '000000001', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', + title: '你收到了 14 份新周报', + datetime: '2017-08-09', + type: 'notification' + }, { + id: '000000002', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png', + title: '你推荐的 曲妮妮 已通过第三轮面试', + datetime: '2017-08-08', + type: 'notification' + }, { + id: '000000003', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png', + title: '这种模板可以区分多种通知类型', + datetime: '2017-08-07', + read: true, + type: 'notification' + }, { + id: '000000004', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + datetime: '2017-08-07', + type: 'notification' + }, { + id: '000000005', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', + title: '内容不要超过两行字,超出时自动截断', + datetime: '2017-08-07', + type: 'notification' + }, { + id: '000000006', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '曲丽丽 评论了你', + description: '描述信息描述信息描述信息', + datetime: '2017-08-07', + type: 'message', + clickClose: true + }, { + id: '000000007', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '朱偏右 回复了你', + description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', + datetime: '2017-08-07', + type: 'message', + clickClose: true + }, { + id: '000000008', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '标题', + description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', + datetime: '2017-08-07', + type: 'message', + clickClose: true + }, { + id: '000000009', + title: '任务名称', + description: '任务需要在 2017-01-12 20:00 前启动', + extra: '未开始', + status: 'todo', + type: 'event' + }, { + id: '000000010', + title: '第三方紧急代码变更', + description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', + extra: '马上到期', + status: 'urgent', + type: 'event' + }, { + id: '000000011', + title: '信息安全考试', + description: '指派竹尔于 2017-01-09 前完成更新并发布', + extra: '已耗时 8 天', + status: 'doing', + type: 'event' + }, { + id: '000000012', + title: 'ABCD 版本发布', + description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', + extra: '进行中', + status: 'processing', + type: 'event' + }]); + + var notices = { + 'GET /api/notices': getNotices + }; + + const basicGoods = [{ + id: '1234561', + name: '矿泉水 550ml', + barcode: '12421432143214321', + price: '2.00', + num: '1', + amount: '2.00' + }, { + id: '1234562', + name: '凉茶 300ml', + barcode: '12421432143214322', + price: '3.00', + num: '2', + amount: '6.00' + }, { + id: '1234563', + name: '好吃的薯片', + barcode: '12421432143214323', + price: '7.00', + num: '4', + amount: '28.00' + }, { + id: '1234564', + name: '特别好吃的蛋卷', + barcode: '12421432143214324', + price: '8.50', + num: '3', + amount: '25.50' + }]; + const basicProgress = [{ + key: '1', + time: '2017-10-01 14:10', + rate: '联系客户', + status: 'processing', + operator: '取货员 ID1234', + cost: '5mins' + }, { + key: '2', + time: '2017-10-01 14:05', + rate: '取货员出发', + status: 'success', + operator: '取货员 ID1234', + cost: '1h' + }, { + key: '3', + time: '2017-10-01 13:05', + rate: '取货员接单', + status: 'success', + operator: '取货员 ID1234', + cost: '5mins' + }, { + key: '4', + time: '2017-10-01 13:00', + rate: '申请审批通过', + status: 'success', + operator: '系统', + cost: '1h' + }, { + key: '5', + time: '2017-10-01 12:00', + rate: '发起退货申请', + status: 'success', + operator: '用户', + cost: '5mins' + }]; + const advancedOperation1 = [{ + key: 'op1', + type: '订购关系生效', + name: '曲丽丽', + status: 'agree', + updatedAt: '2017-10-03 19:23:12', + memo: '-' + }, { + key: 'op2', + type: '财务复审', + name: '付小小', + status: 'reject', + updatedAt: '2017-10-03 19:23:12', + memo: '不通过原因' + }, { + key: 'op3', + type: '部门初审', + name: '周毛毛', + status: 'agree', + updatedAt: '2017-10-03 19:23:12', + memo: '-' + }, { + key: 'op4', + type: '提交订单', + name: '林东东', + status: 'agree', + updatedAt: '2017-10-03 19:23:12', + memo: '很棒' + }, { + key: 'op5', + type: '创建订单', + name: '汗牙牙', + status: 'agree', + updatedAt: '2017-10-03 19:23:12', + memo: '-' + }]; + const advancedOperation2 = [{ + key: 'op1', + type: '订购关系生效', + name: '曲丽丽', + status: 'agree', + updatedAt: '2017-10-03 19:23:12', + memo: '-' + }]; + const advancedOperation3 = [{ + key: 'op1', + type: '创建订单', + name: '汗牙牙', + status: 'agree', + updatedAt: '2017-10-03 19:23:12', + memo: '-' + }]; + const getProfileAdvancedData = { + advancedOperation1, + advancedOperation2, + advancedOperation3 + }; + const { + Random + } = mockjs; + var profile = { + 'GET /api/profile/advanced': getProfileAdvancedData, + 'GET /api/profile/basic': (req, res) => { + const { + id + } = req.query; + const application = { + id, + status: '已取货', + orderNo: Random.id(), + childOrderNo: Random.id() + }; + const userInfo = { + name: Random.cname(), + tel: '18100000000', + delivery: '菜鸟物流', + addr: '浙江省杭州市西湖区万塘路18号', + remark: '备注' + }; + res.json({ + userInfo, + application, + basicGoods, + basicProgress + }); + } + }; + + /*! https://mths.be/punycode v1.4.1 by @mathias */ + + /** Highest positive signed 32-bit float value */ + var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1 + + /** Bootstring parameters */ + + var base = 36; + var tMin = 1; + var tMax = 26; + var skew = 38; + var damp = 700; + var initialBias = 72; + var initialN = 128; // 0x80 + + var delimiter = '-'; // '\x2D' + var regexNonASCII = /[^\x20-\x7E]/; // unprintable ASCII chars + non-ASCII chars + + var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators + + /** Error messages */ + + var errors = { + 'overflow': 'Overflow: input needs wider integers to process', + 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', + 'invalid-input': 'Invalid input' + }; + /** Convenience shortcuts */ + + var baseMinusTMin = base - tMin; + var floor = Math.floor; + var stringFromCharCode = String.fromCharCode; + /*--------------------------------------------------------------------------*/ + + /** + * A generic error utility function. + * @private + * @param {String} type The error type. + * @returns {Error} Throws a `RangeError` with the applicable error message. + */ + + function error(type) { + throw new RangeError(errors[type]); + } + /** + * A generic `Array#map` utility function. + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function that gets called for every array + * item. + * @returns {Array} A new array of values returned by the callback function. + */ + + + function map(array, fn) { + var length = array.length; + var result = []; + + while (length--) { + result[length] = fn(array[length]); + } + + return result; + } + /** + * A simple `Array#map`-like wrapper to work with domain name strings or email + * addresses. + * @private + * @param {String} domain The domain name or email address. + * @param {Function} callback The function that gets called for every + * character. + * @returns {Array} A new string of characters returned by the callback + * function. + */ + + + function mapDomain(string, fn) { + var parts = string.split('@'); + var result = ''; + + if (parts.length > 1) { + // In email addresses, only the domain name should be punycoded. Leave + // the local part (i.e. everything up to `@`) intact. + result = parts[0] + '@'; + string = parts[1]; + } // Avoid `split(regex)` for IE8 compatibility. See #17. + + + string = string.replace(regexSeparators, '\x2E'); + var labels = string.split('.'); + var encoded = map(labels, fn).join('.'); + return result + encoded; + } + /** + * Creates an array containing the numeric code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, + * this function will convert a pair of surrogate halves (each of which + * UCS-2 exposes as separate characters) into a single code point, + * matching UTF-16. + * @see `punycode.ucs2.encode` + * @see + * @memberOf punycode.ucs2 + * @name decode + * @param {String} string The Unicode input string (UCS-2). + * @returns {Array} The new array of code points. + */ + + + function ucs2decode(string) { + var output = [], + counter = 0, + length = string.length, + value, + extra; + + while (counter < length) { + value = string.charCodeAt(counter++); + + if (value >= 0xD800 && value <= 0xDBFF && counter < length) { + // high surrogate, and there is a next character + extra = string.charCodeAt(counter++); + + if ((extra & 0xFC00) == 0xDC00) { + // low surrogate + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + // unmatched surrogate; only append this code unit, in case the next + // code unit is the high surrogate of a surrogate pair + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + + return output; + } + /** + * Converts a digit/integer into a basic code point. + * @see `basicToDigit()` + * @private + * @param {Number} digit The numeric value of a basic code point. + * @returns {Number} The basic code point whose value (when used for + * representing integers) is `digit`, which needs to be in the range + * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is + * used; else, the lowercase form is used. The behavior is undefined + * if `flag` is non-zero and `digit` has no uppercase form. + */ + + + function digitToBasic(digit, flag) { + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); + } + /** + * Bias adaptation function as per section 3.4 of RFC 3492. + * https://tools.ietf.org/html/rfc3492#section-3.4 + * @private + */ + + + function adapt(delta, numPoints, firstTime) { + var k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + + for (; + /* no initialization */ + delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); + } + /** + * Converts a string of Unicode symbols (e.g. a domain name label) to a + * Punycode string of ASCII-only symbols. + * @memberOf punycode + * @param {String} input The string of Unicode symbols. + * @returns {String} The resulting Punycode string of ASCII-only symbols. + */ + + function encode(input) { + var n, + delta, + handledCPCount, + basicLength, + bias, + j, + m, + q, + k, + t, + currentValue, + output = [], + + /** `inputLength` will hold the number of code points in `input`. */ + inputLength, + + /** Cached calculation results */ + handledCPCountPlusOne, + baseMinusT, + qMinusT; // Convert the input in UCS-2 to Unicode + + input = ucs2decode(input); // Cache the length + + inputLength = input.length; // Initialize the state + + n = initialN; + delta = 0; + bias = initialBias; // Handle the basic code points + + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + + if (currentValue < 0x80) { + output.push(stringFromCharCode(currentValue)); + } + } + + handledCPCount = basicLength = output.length; // `handledCPCount` is the number of code points that have been handled; + // `basicLength` is the number of basic code points. + // Finish the basic string - if it is not empty - with a delimiter + + if (basicLength) { + output.push(delimiter); + } // Main encoding loop: + + + while (handledCPCount < inputLength) { + // All non-basic code points < n have been handled already. Find the next + // larger one: + for (m = maxInt, j = 0; j < inputLength; ++j) { + currentValue = input[j]; + + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } // Increase `delta` enough to advance the decoder's state to , + // but guard against overflow + + + handledCPCountPlusOne = handledCPCount + 1; + + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error('overflow'); + } + + delta += (m - n) * handledCPCountPlusOne; + n = m; + + for (j = 0; j < inputLength; ++j) { + currentValue = input[j]; + + if (currentValue < n && ++delta > maxInt) { + error('overflow'); + } + + if (currentValue == n) { + // Represent delta as a generalized variable-length integer + for (q = delta, k = base;; + /* no condition */ + k += base) { + t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; + + if (q < t) { + break; + } + + qMinusT = q - t; + baseMinusT = base - t; + output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))); + q = floor(qMinusT / baseMinusT); + } + + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength); + delta = 0; + ++handledCPCount; + } + } + + ++delta; + ++n; + } + + return output.join(''); + } + /** + * Converts a Unicode string representing a domain name or an email address to + * Punycode. Only the non-ASCII parts of the domain name will be converted, + * i.e. it doesn't matter if you call it with a domain that's already in + * ASCII. + * @memberOf punycode + * @param {String} input The domain name or email address to convert, as a + * Unicode string. + * @returns {String} The Punycode representation of the given domain name or + * email address. + */ + + function toASCII(input) { + return mapDomain(input, function (string) { + return regexNonASCII.test(string) ? 'xn--' + encode(string) : string; + }); + } + + // shim for using process in browser + + if (typeof global.setTimeout === 'function') ; + + if (typeof global.clearTimeout === 'function') ; + + var performance = global.performance || {}; + + var performanceNow = performance.now || performance.mozNow || performance.msNow || performance.oNow || performance.webkitNow || function () { + return new Date().getTime(); + }; // generate timestamp or delta + + // Copyright Joyent, Inc. and other Node contributors. + function isNull(arg) { + return arg === null; + } + function isNullOrUndefined(arg) { + return arg == null; + } + function isString(arg) { + return typeof arg === 'string'; + } + function isObject(arg) { + return typeof arg === 'object' && arg !== null; + } + + // Copyright Joyent, Inc. and other Node contributors. + // + // Permission is hereby granted, free of charge, to any person obtaining a + // copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to permit + // persons to whom the Software is furnished to do so, subject to the + // following conditions: + // + // The above copyright notice and this permission notice shall be included + // in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + // USE OR OTHER DEALINGS IN THE SOFTWARE. + // If obj.hasOwnProperty has been overridden, then calling + // obj.hasOwnProperty(prop) will break. + // See: https://github.com/joyent/node/issues/1707 + function hasOwnProperty(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); + } + + var isArray = Array.isArray || function (xs) { + return Object.prototype.toString.call(xs) === '[object Array]'; + }; + + function stringifyPrimitive(v) { + switch (typeof v) { + case 'string': + return v; + + case 'boolean': + return v ? 'true' : 'false'; + + case 'number': + return isFinite(v) ? v : ''; + + default: + return ''; + } + } + + function stringify(obj, sep, eq, name) { + sep = sep || '&'; + eq = eq || '='; + + if (obj === null) { + obj = undefined; + } + + if (typeof obj === 'object') { + return map$1(objectKeys(obj), function (k) { + var ks = encodeURIComponent(stringifyPrimitive(k)) + eq; + + if (isArray(obj[k])) { + return map$1(obj[k], function (v) { + return ks + encodeURIComponent(stringifyPrimitive(v)); + }).join(sep); + } else { + return ks + encodeURIComponent(stringifyPrimitive(obj[k])); + } + }).join(sep); + } + + if (!name) return ''; + return encodeURIComponent(stringifyPrimitive(name)) + eq + encodeURIComponent(stringifyPrimitive(obj)); + } + + function map$1(xs, f) { + if (xs.map) return xs.map(f); + var res = []; + + for (var i = 0; i < xs.length; i++) { + res.push(f(xs[i], i)); + } + + return res; + } + + var objectKeys = Object.keys || function (obj) { + var res = []; + + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key); + } + + return res; + }; + + function parse(qs, sep, eq, options) { + sep = sep || '&'; + eq = eq || '='; + var obj = {}; + + if (typeof qs !== 'string' || qs.length === 0) { + return obj; + } + + var regexp = /\+/g; + qs = qs.split(sep); + var maxKeys = 1000; + + if (options && typeof options.maxKeys === 'number') { + maxKeys = options.maxKeys; + } + + var len = qs.length; // maxKeys <= 0 means that we should not limit keys count + + if (maxKeys > 0 && len > maxKeys) { + len = maxKeys; + } + + for (var i = 0; i < len; ++i) { + var x = qs[i].replace(regexp, '%20'), + idx = x.indexOf(eq), + kstr, + vstr, + k, + v; + + if (idx >= 0) { + kstr = x.substr(0, idx); + vstr = x.substr(idx + 1); + } else { + kstr = x; + vstr = ''; + } + + k = decodeURIComponent(kstr); + v = decodeURIComponent(vstr); + + if (!hasOwnProperty(obj, k)) { + obj[k] = v; + } else if (isArray(obj[k])) { + obj[k].push(v); + } else { + obj[k] = [obj[k], v]; + } + } + + return obj; + } + + // Copyright Joyent, Inc. and other Node contributors. + function Url() { + this.protocol = null; + this.slashes = null; + this.auth = null; + this.host = null; + this.port = null; + this.hostname = null; + this.hash = null; + this.search = null; + this.query = null; + this.pathname = null; + this.path = null; + this.href = null; + } // Reference: RFC 3986, RFC 1808, RFC 2396 + // define these here so at least they only have to be + // compiled once on the first module load. + + var protocolPattern = /^([a-z0-9.+-]+:)/i, + portPattern = /:[0-9]*$/, + // Special case for a simple path URL + simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/, + // RFC 2396: characters reserved for delimiting URLs. + // We actually just auto-escape these. + delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], + // RFC 2396: characters not allowed for various reasons. + unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), + // Allowed by RFCs, but cause of XSS attacks. Always escape these. + autoEscape = ['\''].concat(unwise), + // Characters that are never ever allowed in a hostname. + // Note that any invalid chars are also handled, but these + // are the ones that are *expected* to be seen, so we fast-path + // them. + nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), + hostEndingChars = ['/', '?', '#'], + hostnameMaxLen = 255, + hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, + hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, + // protocols that can allow "unsafe" and "unwise" chars. + unsafeProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that never have a hostname. + hostlessProtocol = { + 'javascript': true, + 'javascript:': true + }, + // protocols that always contain a // bit. + slashedProtocol = { + 'http': true, + 'https': true, + 'ftp': true, + 'gopher': true, + 'file': true, + 'http:': true, + 'https:': true, + 'ftp:': true, + 'gopher:': true, + 'file:': true + }; + + function urlParse(url, parseQueryString, slashesDenoteHost) { + if (url && isObject(url) && url instanceof Url) return url; + var u = new Url(); + u.parse(url, parseQueryString, slashesDenoteHost); + return u; + } + + Url.prototype.parse = function (url, parseQueryString, slashesDenoteHost) { + return parse$1(this, url, parseQueryString, slashesDenoteHost); + }; + + function parse$1(self, url, parseQueryString, slashesDenoteHost) { + if (!isString(url)) { + throw new TypeError('Parameter \'url\' must be a string, not ' + typeof url); + } // Copy chrome, IE, opera backslash-handling behavior. + // Back slashes before the query string get converted to forward slashes + // See: https://code.google.com/p/chromium/issues/detail?id=25916 + + + var queryIndex = url.indexOf('?'), + splitter = queryIndex !== -1 && queryIndex < url.indexOf('#') ? '?' : '#', + uSplit = url.split(splitter), + slashRegex = /\\/g; + uSplit[0] = uSplit[0].replace(slashRegex, '/'); + url = uSplit.join(splitter); + var rest = url; // trim before proceeding. + // This is to support parse stuff like " http://foo.com \n" + + rest = rest.trim(); + + if (!slashesDenoteHost && url.split('#').length === 1) { + // Try fast path regexp + var simplePath = simplePathPattern.exec(rest); + + if (simplePath) { + self.path = rest; + self.href = rest; + self.pathname = simplePath[1]; + + if (simplePath[2]) { + self.search = simplePath[2]; + + if (parseQueryString) { + self.query = parse(self.search.substr(1)); + } else { + self.query = self.search.substr(1); + } + } else if (parseQueryString) { + self.search = ''; + self.query = {}; + } + + return self; + } + } + + var proto = protocolPattern.exec(rest); + + if (proto) { + proto = proto[0]; + var lowerProto = proto.toLowerCase(); + self.protocol = lowerProto; + rest = rest.substr(proto.length); + } // figure out if it's got a host + // user@server is *always* interpreted as a hostname, and url + // resolution will treat //foo/bar as host=foo,path=bar because that's + // how the browser resolves relative URLs. + + + if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { + var slashes = rest.substr(0, 2) === '//'; + + if (slashes && !(proto && hostlessProtocol[proto])) { + rest = rest.substr(2); + self.slashes = true; + } + } + + var i, hec, l, p; + + if (!hostlessProtocol[proto] && (slashes || proto && !slashedProtocol[proto])) { + // there's a hostname. + // the first instance of /, ?, ;, or # ends the host. + // + // If there is an @ in the hostname, then non-host chars *are* allowed + // to the left of the last @ sign, unless some host-ending character + // comes *before* the @-sign. + // URLs are obnoxious. + // + // ex: + // http://a@b@c/ => user:a@b host:c + // http://a@b?@c => user:a host:c path:/?@c + // v0.12 TODO(isaacs): This is not quite how Chrome does things. + // Review our test case against browsers more comprehensively. + // find the first instance of any hostEndingChars + var hostEnd = -1; + + for (i = 0; i < hostEndingChars.length; i++) { + hec = rest.indexOf(hostEndingChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) hostEnd = hec; + } // at this point, either we have an explicit point where the + // auth portion cannot go past, or the last @ char is the decider. + + + var auth, atSign; + + if (hostEnd === -1) { + // atSign can be anywhere. + atSign = rest.lastIndexOf('@'); + } else { + // atSign must be in auth portion. + // http://a@b/c@d => host:b auth:a path:/c@d + atSign = rest.lastIndexOf('@', hostEnd); + } // Now we have a portion which is definitely the auth. + // Pull that off. + + + if (atSign !== -1) { + auth = rest.slice(0, atSign); + rest = rest.slice(atSign + 1); + self.auth = decodeURIComponent(auth); + } // the host is the remaining to the left of the first non-host char + + + hostEnd = -1; + + for (i = 0; i < nonHostChars.length; i++) { + hec = rest.indexOf(nonHostChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) hostEnd = hec; + } // if we still have not hit it, then the entire thing is a host. + + + if (hostEnd === -1) hostEnd = rest.length; + self.host = rest.slice(0, hostEnd); + rest = rest.slice(hostEnd); // pull out port. + + parseHost(self); // we've indicated that there is a hostname, + // so even if it's empty, it has to be present. + + self.hostname = self.hostname || ''; // if hostname begins with [ and ends with ] + // assume that it's an IPv6 address. + + var ipv6Hostname = self.hostname[0] === '[' && self.hostname[self.hostname.length - 1] === ']'; // validate a little. + + if (!ipv6Hostname) { + var hostparts = self.hostname.split(/\./); + + for (i = 0, l = hostparts.length; i < l; i++) { + var part = hostparts[i]; + if (!part) continue; + + if (!part.match(hostnamePartPattern)) { + var newpart = ''; + + for (var j = 0, k = part.length; j < k; j++) { + if (part.charCodeAt(j) > 127) { + // we replace non-ASCII char with a temporary placeholder + // we need this to make sure size of hostname is not + // broken by replacing non-ASCII by nothing + newpart += 'x'; + } else { + newpart += part[j]; + } + } // we test again with ASCII char only + + + if (!newpart.match(hostnamePartPattern)) { + var validParts = hostparts.slice(0, i); + var notHost = hostparts.slice(i + 1); + var bit = part.match(hostnamePartStart); + + if (bit) { + validParts.push(bit[1]); + notHost.unshift(bit[2]); + } + + if (notHost.length) { + rest = '/' + notHost.join('.') + rest; + } + + self.hostname = validParts.join('.'); + break; + } + } + } + } + + if (self.hostname.length > hostnameMaxLen) { + self.hostname = ''; + } else { + // hostnames are always lower case. + self.hostname = self.hostname.toLowerCase(); + } + + if (!ipv6Hostname) { + // IDNA Support: Returns a punycoded representation of "domain". + // It only converts parts of the domain name that + // have non-ASCII characters, i.e. it doesn't matter if + // you call it with a domain that already is ASCII-only. + self.hostname = toASCII(self.hostname); + } + + p = self.port ? ':' + self.port : ''; + var h = self.hostname || ''; + self.host = h + p; + self.href += self.host; // strip [ and ] from the hostname + // the host field still retains them, though + + if (ipv6Hostname) { + self.hostname = self.hostname.substr(1, self.hostname.length - 2); + + if (rest[0] !== '/') { + rest = '/' + rest; + } + } + } // now rest is set to the post-host stuff. + // chop off any delim chars. + + + if (!unsafeProtocol[lowerProto]) { + // First, make 100% sure that any "autoEscape" chars get + // escaped, even if encodeURIComponent doesn't think they + // need to be. + for (i = 0, l = autoEscape.length; i < l; i++) { + var ae = autoEscape[i]; + if (rest.indexOf(ae) === -1) continue; + var esc = encodeURIComponent(ae); + + if (esc === ae) { + esc = escape(ae); + } + + rest = rest.split(ae).join(esc); + } + } // chop off from the tail first. + + + var hash = rest.indexOf('#'); + + if (hash !== -1) { + // got a fragment string. + self.hash = rest.substr(hash); + rest = rest.slice(0, hash); + } + + var qm = rest.indexOf('?'); + + if (qm !== -1) { + self.search = rest.substr(qm); + self.query = rest.substr(qm + 1); + + if (parseQueryString) { + self.query = parse(self.query); + } + + rest = rest.slice(0, qm); + } else if (parseQueryString) { + // no query string, but parseQueryString still requested + self.search = ''; + self.query = {}; + } + + if (rest) self.pathname = rest; + + if (slashedProtocol[lowerProto] && self.hostname && !self.pathname) { + self.pathname = '/'; + } //to support http.request + + + if (self.pathname || self.search) { + p = self.pathname || ''; + var s = self.search || ''; + self.path = p + s; + } // finally, reconstruct the href based on what has been validated. + + + self.href = format(self); + return self; + } // format a parsed object into a url string + + function format(self) { + var auth = self.auth || ''; + + if (auth) { + auth = encodeURIComponent(auth); + auth = auth.replace(/%3A/i, ':'); + auth += '@'; + } + + var protocol = self.protocol || '', + pathname = self.pathname || '', + hash = self.hash || '', + host = false, + query = ''; + + if (self.host) { + host = auth + self.host; + } else if (self.hostname) { + host = auth + (self.hostname.indexOf(':') === -1 ? self.hostname : '[' + this.hostname + ']'); + + if (self.port) { + host += ':' + self.port; + } + } + + if (self.query && isObject(self.query) && Object.keys(self.query).length) { + query = stringify(self.query); + } + + var search = self.search || query && '?' + query || ''; + if (protocol && protocol.substr(-1) !== ':') protocol += ':'; // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. + // unless they had them to begin with. + + if (self.slashes || (!protocol || slashedProtocol[protocol]) && host !== false) { + host = '//' + (host || ''); + if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; + } else if (!host) { + host = ''; + } + + if (hash && hash.charAt(0) !== '#') hash = '#' + hash; + if (search && search.charAt(0) !== '?') search = '?' + search; + pathname = pathname.replace(/[?#]/g, function (match) { + return encodeURIComponent(match); + }); + search = search.replace('#', '%23'); + return protocol + host + pathname + search + hash; + } + + Url.prototype.format = function () { + return format(this); + }; + + Url.prototype.resolve = function (relative) { + return this.resolveObject(urlParse(relative, false, true)).format(); + }; + + Url.prototype.resolveObject = function (relative) { + if (isString(relative)) { + var rel = new Url(); + rel.parse(relative, false, true); + relative = rel; + } + + var result = new Url(); + var tkeys = Object.keys(this); + + for (var tk = 0; tk < tkeys.length; tk++) { + var tkey = tkeys[tk]; + result[tkey] = this[tkey]; + } // hash is always overridden, no matter what. + // even href="" will remove it. + + + result.hash = relative.hash; // if the relative url is empty, then there's nothing left to do here. + + if (relative.href === '') { + result.href = result.format(); + return result; + } // hrefs like //foo/bar always cut to the protocol. + + + if (relative.slashes && !relative.protocol) { + // take everything except the protocol from relative + var rkeys = Object.keys(relative); + + for (var rk = 0; rk < rkeys.length; rk++) { + var rkey = rkeys[rk]; + if (rkey !== 'protocol') result[rkey] = relative[rkey]; + } //urlParse appends trailing / to urls like http://www.example.com + + + if (slashedProtocol[result.protocol] && result.hostname && !result.pathname) { + result.path = result.pathname = '/'; + } + + result.href = result.format(); + return result; + } + + var relPath; + + if (relative.protocol && relative.protocol !== result.protocol) { + // if it's a known url protocol, then changing + // the protocol does weird things + // first, if it's not file:, then we MUST have a host, + // and if there was a path + // to begin with, then we MUST have a path. + // if it is file:, then the host is dropped, + // because that's known to be hostless. + // anything else is assumed to be absolute. + if (!slashedProtocol[relative.protocol]) { + var keys = Object.keys(relative); + + for (var v = 0; v < keys.length; v++) { + var k = keys[v]; + result[k] = relative[k]; + } + + result.href = result.format(); + return result; + } + + result.protocol = relative.protocol; + + if (!relative.host && !hostlessProtocol[relative.protocol]) { + relPath = (relative.pathname || '').split('/'); + + while (relPath.length && !(relative.host = relPath.shift())); + + if (!relative.host) relative.host = ''; + if (!relative.hostname) relative.hostname = ''; + if (relPath[0] !== '') relPath.unshift(''); + if (relPath.length < 2) relPath.unshift(''); + result.pathname = relPath.join('/'); + } else { + result.pathname = relative.pathname; + } + + result.search = relative.search; + result.query = relative.query; + result.host = relative.host || ''; + result.auth = relative.auth; + result.hostname = relative.hostname || relative.host; + result.port = relative.port; // to support http.request + + if (result.pathname || result.search) { + var p = result.pathname || ''; + var s = result.search || ''; + result.path = p + s; + } + + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; + } + + var isSourceAbs = result.pathname && result.pathname.charAt(0) === '/', + isRelAbs = relative.host || relative.pathname && relative.pathname.charAt(0) === '/', + mustEndAbs = isRelAbs || isSourceAbs || result.host && relative.pathname, + removeAllDots = mustEndAbs, + srcPath = result.pathname && result.pathname.split('/') || [], + psychotic = result.protocol && !slashedProtocol[result.protocol]; + relPath = relative.pathname && relative.pathname.split('/') || []; // if the url is a non-slashed url, then relative + // links like ../.. should be able + // to crawl up to the hostname, as well. This is strange. + // result.protocol has already been set by now. + // Later on, put the first path part into the host field. + + if (psychotic) { + result.hostname = ''; + result.port = null; + + if (result.host) { + if (srcPath[0] === '') srcPath[0] = result.host;else srcPath.unshift(result.host); + } + + result.host = ''; + + if (relative.protocol) { + relative.hostname = null; + relative.port = null; + + if (relative.host) { + if (relPath[0] === '') relPath[0] = relative.host;else relPath.unshift(relative.host); + } + + relative.host = null; + } + + mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); + } + + var authInHost; + + if (isRelAbs) { + // it's absolute. + result.host = relative.host || relative.host === '' ? relative.host : result.host; + result.hostname = relative.hostname || relative.hostname === '' ? relative.hostname : result.hostname; + result.search = relative.search; + result.query = relative.query; + srcPath = relPath; // fall through to the dot-handling below. + } else if (relPath.length) { + // it's relative + // throw away the existing file, and take the new path instead. + if (!srcPath) srcPath = []; + srcPath.pop(); + srcPath = srcPath.concat(relPath); + result.search = relative.search; + result.query = relative.query; + } else if (!isNullOrUndefined(relative.search)) { + // just pull out the search. + // like href='?foo'. + // Put this after the other two cases because it simplifies the booleans + if (psychotic) { + result.hostname = result.host = srcPath.shift(); //occationaly the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + + authInHost = result.host && result.host.indexOf('@') > 0 ? result.host.split('@') : false; + + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + + result.search = relative.search; + result.query = relative.query; //to support http.request + + if (!isNull(result.pathname) || !isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + (result.search ? result.search : ''); + } + + result.href = result.format(); + return result; + } + + if (!srcPath.length) { + // no path at all. easy. + // we've already handled the other stuff above. + result.pathname = null; //to support http.request + + if (result.search) { + result.path = '/' + result.search; + } else { + result.path = null; + } + + result.href = result.format(); + return result; + } // if a url ENDs in . or .., then it must get a trailing slash. + // however, if it ends in anything else non-slashy, + // then it must NOT get a trailing slash. + + + var last = srcPath.slice(-1)[0]; + var hasTrailingSlash = (result.host || relative.host || srcPath.length > 1) && (last === '.' || last === '..') || last === ''; // strip single dots, resolve double dots to parent dir + // if the path tries to go above the root, `up` ends up > 0 + + var up = 0; + + for (var i = srcPath.length; i >= 0; i--) { + last = srcPath[i]; + + if (last === '.') { + srcPath.splice(i, 1); + } else if (last === '..') { + srcPath.splice(i, 1); + up++; + } else if (up) { + srcPath.splice(i, 1); + up--; + } + } // if the path is allowed to go above the root, restore leading ..s + + + if (!mustEndAbs && !removeAllDots) { + for (; up--; up) { + srcPath.unshift('..'); + } + } + + if (mustEndAbs && srcPath[0] !== '' && (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { + srcPath.unshift(''); + } + + if (hasTrailingSlash && srcPath.join('/').substr(-1) !== '/') { + srcPath.push(''); + } + + var isAbsolute = srcPath[0] === '' || srcPath[0] && srcPath[0].charAt(0) === '/'; // put the host back + + if (psychotic) { + result.hostname = result.host = isAbsolute ? '' : srcPath.length ? srcPath.shift() : ''; //occationaly the auth can get stuck only in host + //this especially happens in cases like + //url.resolveObject('mailto:local1@domain1', 'local2@domain2') + + authInHost = result.host && result.host.indexOf('@') > 0 ? result.host.split('@') : false; + + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + + mustEndAbs = mustEndAbs || result.host && srcPath.length; + + if (mustEndAbs && !isAbsolute) { + srcPath.unshift(''); + } + + if (!srcPath.length) { + result.pathname = null; + result.path = null; + } else { + result.pathname = srcPath.join('/'); + } //to support request.http + + + if (!isNull(result.pathname) || !isNull(result.search)) { + result.path = (result.pathname ? result.pathname : '') + (result.search ? result.search : ''); + } + + result.auth = relative.auth || result.auth; + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; + }; + + Url.prototype.parseHost = function () { + return parseHost(this); + }; + + function parseHost(self) { + var host = self.host; + var port = portPattern.exec(host); + + if (port) { + port = port[0]; + + if (port !== ':') { + self.port = port.substr(1); + } + + host = host.substr(0, host.length - port.length); + } + + if (host) self.hostname = host; + } + + let tableListDataSource = []; + + for (let i = 0; i < 46; i += 1) { + tableListDataSource.push({ + key: i, + disabled: i % 6 === 0, + href: 'https://ant.design', + avatar: ['https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png'][i % 2], + name: `TradeCode ${i}`, + title: `一个任务名称 ${i}`, + owner: '曲丽丽', + desc: '这是一段描述', + callNo: Math.floor(Math.random() * 1000), + status: Math.floor(Math.random() * 10) % 4, + updatedAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`), + createdAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`), + progress: Math.ceil(Math.random() * 100) + }); + } + + function getRule(req, res, u) { + let url = u; + + if (!url || Object.prototype.toString.call(url) !== '[object String]') { + url = req.url; // eslint-disable-line + } + + const params = urlParse(url, true).query; + let dataSource = tableListDataSource; + + if (params.sorter) { + const s = params.sorter.split('_'); + dataSource = dataSource.sort((prev, next) => { + if (s[1] === 'descend') { + return next[s[0]] - prev[s[0]]; + } + + return prev[s[0]] - next[s[0]]; + }); + } + + if (params.status) { + const status = params.status.split(','); + let filterDataSource = []; + status.forEach(s => { + filterDataSource = filterDataSource.concat(dataSource.filter(data => parseInt(data.status, 10) === parseInt(s[0], 10))); + }); + dataSource = filterDataSource; + } + + if (params.name) { + dataSource = dataSource.filter(data => data.name.indexOf(params.name) > -1); + } + + let pageSize = 10; + + if (params.pageSize) { + pageSize = params.pageSize * 1; + } + + const result = { + list: dataSource, + pagination: { + total: dataSource.length, + pageSize, + current: parseInt(params.currentPage, 10) || 1 + } + }; + return res.json(result); + } + + function postRule(req, res, u, b) { + let url = u; + + if (!url || Object.prototype.toString.call(url) !== '[object String]') { + url = req.url; // eslint-disable-line + } + + const body = b && b.body || req.body; + const { + method, + name, + desc, + key + } = body; + + switch (method) { + /* eslint no-case-declarations:0 */ + case 'delete': + tableListDataSource = tableListDataSource.filter(item => key.indexOf(item.key) === -1); + break; + + case 'post': + const i = Math.ceil(Math.random() * 10000); + tableListDataSource.unshift({ + key: i, + href: 'https://ant.design', + avatar: ['https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png'][i % 2], + name: `TradeCode ${i}`, + title: `一个任务名称 ${i}`, + owner: '曲丽丽', + desc, + callNo: Math.floor(Math.random() * 1000), + status: Math.floor(Math.random() * 10) % 2, + updatedAt: new Date(), + createdAt: new Date(), + progress: Math.ceil(Math.random() * 100) + }); + break; + + case 'update': + tableListDataSource = tableListDataSource.map(item => { + if (item.key === key) { + Object.assign(item, { + desc, + name + }); + return item; + } + + return item; + }); + break; + + default: + break; + } + + return getRule(req, res, u); + } + + var rule = { + 'GET /api/rule': getRule, + 'POST /api/rule': postRule + }; + + // 代码中会兼容本地 service mock 以及部署站点的静态数据 + var user$1 = { + // 支持值为 Object 和 Array + 'GET /api/currentUser': { + name: 'Serati Ma', + avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png', + userid: '00000001', + email: 'antdesign@alipay.com', + signature: '海纳百川,有容乃大', + title: '交互专家', + group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED', + tags: [ + { + key: '0', + label: '很有想法的', + }, + { + key: '1', + label: '专注设计', + }, + { + key: '2', + label: '辣~', + }, + { + key: '3', + label: '大长腿', + }, + { + key: '4', + label: '川妹子', + }, + { + key: '5', + label: '海纳百川', + }, + ], + notice: [ + { + id: 'xxx1', + title: titles[0], + logo: avatars[0], + description: '那是一种内在的东西,他们到达不了,也无法触及的', + updatedAt: new Date(), + member: '科学搬砖组', + href: '', + memberLink: '', + }, + { + id: 'xxx2', + title: titles[1], + logo: avatars[1], + description: '希望是一个好东西,也许是最好的,好东西是不会消亡的', + updatedAt: new Date('2017-07-24'), + member: '全组都是吴彦祖', + href: '', + memberLink: '', + }, + { + id: 'xxx3', + title: titles[2], + logo: avatars[2], + description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆', + updatedAt: new Date(), + member: '中二少女团', + href: '', + memberLink: '', + }, + { + id: 'xxx4', + title: titles[3], + logo: avatars[3], + description: '那时候我只会想自己想要什么,从不想自己拥有什么', + updatedAt: new Date('2017-07-23'), + member: '程序员日常', + href: '', + memberLink: '', + }, + { + id: 'xxx5', + title: titles[4], + logo: avatars[4], + description: '凛冬将至', + updatedAt: new Date('2017-07-23'), + member: '高逼格设计天团', + href: '', + memberLink: '', + }, + { + id: 'xxx6', + title: titles[5], + logo: avatars[5], + description: '生命就像一盒巧克力,结果往往出人意料', + updatedAt: new Date('2017-07-23'), + member: '骗你来学计算机', + href: '', + memberLink: '', + }, + ], + notifyCount: 12, + unreadCount: 11, + country: 'China', + geographic: { + province: { + label: '浙江省', + key: '330000' + }, + city: { + label: '杭州市', + key: '330100' + } + }, + address: '西湖区工专路 77 号', + phone: '0752-268888888' + }, + // GET POST 可省略 + 'GET /api/users': [{ + key: '1', + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park' + }, { + key: '2', + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park' + }, { + key: '3', + name: 'Joe Black', + age: 32, + address: 'Sidney No. 1 Lake Park' + }], + 'POST /api/login/account': (req, res) => { + const { + password, + userName, + type + } = req.body; + + if (password === 'ant.design' && userName === 'admin') { + res.send({ + status: 'ok', + type, + currentAuthority: 'admin' + }); + return; + } + + if (password === 'ant.design' && userName === 'user') { + res.send({ + status: 'ok', + type, + currentAuthority: 'user' + }); + return; + } + + res.send({ + status: 'error', + type, + currentAuthority: 'guest' + }); + }, + 'POST /api/register': (req, res) => { + res.send({ + status: 'ok', + currentAuthority: 'user' + }); + }, + 'GET /api/500': (req, res) => { + res.status(500).send({ + timestamp: 1513932555104, + status: 500, + error: 'error', + message: 'error', + path: '/base/category/list' + }); + }, + 'GET /api/404': (req, res) => { + res.status(404).send({ + timestamp: 1513932643431, + status: 404, + error: 'Not Found', + message: 'No message available', + path: '/base/category/list/2121212' + }); + }, + 'GET /api/403': (req, res) => { + res.status(403).send({ + timestamp: 1513932555104, + status: 403, + error: 'Unauthorized', + message: 'Unauthorized', + path: '/base/category/list' + }); + }, + 'GET /api/401': (req, res) => { + res.status(401).send({ + timestamp: 1513932555104, + status: 401, + error: 'Unauthorized', + message: 'Unauthorized', + path: '/base/category/list' + }); + } + }; + + const data = _objectSpread({}, api, chart, geographic, notices, profile, rule, user$1); + + return data; + +})); diff --git a/mock/api.js b/mock/api.js deleted file mode 100644 index 0286d072fc..0000000000 --- a/mock/api.js +++ /dev/null @@ -1,336 +0,0 @@ -import mockjs from 'mockjs'; - -const titles = [ - 'Alipay', - 'Angular', - 'Ant Design', - 'Ant Design Pro', - 'Bootstrap', - 'React', - 'Vue', - 'Webpack', -]; -const avatars = [ - 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png', // Alipay - 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png', // Angular - 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png', // Ant Design - 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png', // Ant Design Pro - 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png', // Bootstrap - 'https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png', // React - 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png', // Vue - 'https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png', // Webpack -]; - -const avatars2 = [ - 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png', - 'https://gw.alipayobjects.com/zos/rmsportal/cnrhVkzwxjPwAaCfPbdc.png', - 'https://gw.alipayobjects.com/zos/rmsportal/gaOngJwsRYRaVAuXXcmB.png', - 'https://gw.alipayobjects.com/zos/rmsportal/ubnKSIfAJTxIgXOKlciN.png', - 'https://gw.alipayobjects.com/zos/rmsportal/WhxKECPNujWoWEFNdnJE.png', - 'https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png', - 'https://gw.alipayobjects.com/zos/rmsportal/psOgztMplJMGpVEqfcgF.png', - 'https://gw.alipayobjects.com/zos/rmsportal/ZpBqSxLxVEXfcUNoPKrz.png', - 'https://gw.alipayobjects.com/zos/rmsportal/laiEnJdGHVOhJrUShBaJ.png', - 'https://gw.alipayobjects.com/zos/rmsportal/UrQsqscbKEpNuJcvBZBu.png', -]; - -const covers = [ - 'https://gw.alipayobjects.com/zos/rmsportal/uMfMFlvUuceEyPpotzlq.png', - 'https://gw.alipayobjects.com/zos/rmsportal/iZBVOIhGJiAnhplqjvZW.png', - 'https://gw.alipayobjects.com/zos/rmsportal/iXjVmWVHbCJAyqvDxdtx.png', - 'https://gw.alipayobjects.com/zos/rmsportal/gLaIAoVWTtLbBWZNYEMg.png', -]; -const desc = [ - '那是一种内在的东西, 他们到达不了,也无法触及的', - '希望是一个好东西,也许是最好的,好东西是不会消亡的', - '生命就像一盒巧克力,结果往往出人意料', - '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆', - '那时候我只会想自己想要什么,从不想自己拥有什么', -]; - -const user = [ - '付小小', - '曲丽丽', - '林东东', - '周星星', - '吴加好', - '朱偏右', - '鱼酱', - '乐哥', - '谭小仪', - '仲尼', -]; - -function fakeList(count) { - const list = []; - for (let i = 0; i < count; i += 1) { - list.push({ - id: `fake-list-${i}`, - owner: user[i % 10], - title: titles[i % 8], - avatar: avatars[i % 8], - cover: parseInt(i / 4, 10) % 2 === 0 ? covers[i % 4] : covers[3 - (i % 4)], - status: ['active', 'exception', 'normal'][i % 3], - percent: Math.ceil(Math.random() * 50) + 50, - logo: avatars[i % 8], - href: 'https://ant.design', - updatedAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 2 * i), - createdAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 2 * i), - subDescription: desc[i % 5], - description: - '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。', - activeUser: Math.ceil(Math.random() * 100000) + 100000, - newUser: Math.ceil(Math.random() * 1000) + 1000, - star: Math.ceil(Math.random() * 100) + 100, - like: Math.ceil(Math.random() * 100) + 100, - message: Math.ceil(Math.random() * 10) + 10, - content: - '段落示意:蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。蚂蚁金服设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态,提供跨越设计与开发的体验解决方案。', - members: [ - { - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ZiESqWwCXBRQoaPONSJe.png', - name: '曲丽丽', - id: 'member1', - }, - { - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/tBOxZPlITHqwlGjsJWaF.png', - name: '王昭君', - id: 'member2', - }, - { - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/sBxjgqiuHMGRkIjqlQCd.png', - name: '董娜娜', - id: 'member3', - }, - ], - }); - } - - return list; -} - -let sourceData; - -function getFakeList(req, res) { - const params = req.query; - - const count = params.count * 1 || 20; - - const result = fakeList(count); - sourceData = result; - return res.json(result); -} - -function postFakeList(req, res) { - const { /* url = '', */ body } = req; - // const params = getUrlParams(url); - const { method, id } = body; - // const count = (params.count * 1) || 20; - let result = sourceData; - - switch (method) { - case 'delete': - result = result.filter(item => item.id !== id); - break; - case 'update': - result.forEach((item, i) => { - if (item.id === id) { - result[i] = Object.assign(item, body); - } - }); - break; - case 'post': - result.unshift({ - body, - id: `fake-list-${result.length}`, - createdAt: new Date().getTime(), - }); - break; - default: - break; - } - - return res.json(result); -} - -const getNotice = [ - { - id: 'xxx1', - title: titles[0], - logo: avatars[0], - description: '那是一种内在的东西,他们到达不了,也无法触及的', - updatedAt: new Date(), - member: '科学搬砖组', - href: '', - memberLink: '', - }, - { - id: 'xxx2', - title: titles[1], - logo: avatars[1], - description: '希望是一个好东西,也许是最好的,好东西是不会消亡的', - updatedAt: new Date('2017-07-24'), - member: '全组都是吴彦祖', - href: '', - memberLink: '', - }, - { - id: 'xxx3', - title: titles[2], - logo: avatars[2], - description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆', - updatedAt: new Date(), - member: '中二少女团', - href: '', - memberLink: '', - }, - { - id: 'xxx4', - title: titles[3], - logo: avatars[3], - description: '那时候我只会想自己想要什么,从不想自己拥有什么', - updatedAt: new Date('2017-07-23'), - member: '程序员日常', - href: '', - memberLink: '', - }, - { - id: 'xxx5', - title: titles[4], - logo: avatars[4], - description: '凛冬将至', - updatedAt: new Date('2017-07-23'), - member: '高逼格设计天团', - href: '', - memberLink: '', - }, - { - id: 'xxx6', - title: titles[5], - logo: avatars[5], - description: '生命就像一盒巧克力,结果往往出人意料', - updatedAt: new Date('2017-07-23'), - member: '骗你来学计算机', - href: '', - memberLink: '', - }, -]; - -const getActivities = [ - { - id: 'trend-1', - updatedAt: new Date(), - user: { - name: '曲丽丽', - avatar: avatars2[0], - }, - group: { - name: '高逼格设计天团', - link: 'http://github.com/', - }, - project: { - name: '六月迭代', - link: 'http://github.com/', - }, - template: '在 @{group} 新建项目 @{project}', - }, - { - id: 'trend-2', - updatedAt: new Date(), - user: { - name: '付小小', - avatar: avatars2[1], - }, - group: { - name: '高逼格设计天团', - link: 'http://github.com/', - }, - project: { - name: '六月迭代', - link: 'http://github.com/', - }, - template: '在 @{group} 新建项目 @{project}', - }, - { - id: 'trend-3', - updatedAt: new Date(), - user: { - name: '林东东', - avatar: avatars2[2], - }, - group: { - name: '中二少女团', - link: 'http://github.com/', - }, - project: { - name: '六月迭代', - link: 'http://github.com/', - }, - template: '在 @{group} 新建项目 @{project}', - }, - { - id: 'trend-4', - updatedAt: new Date(), - user: { - name: '周星星', - avatar: avatars2[4], - }, - project: { - name: '5 月日常迭代', - link: 'http://github.com/', - }, - template: '将 @{project} 更新至已发布状态', - }, - { - id: 'trend-5', - updatedAt: new Date(), - user: { - name: '朱偏右', - avatar: avatars2[3], - }, - project: { - name: '工程效能', - link: 'http://github.com/', - }, - comment: { - name: '留言', - link: 'http://github.com/', - }, - template: '在 @{project} 发布了 @{comment}', - }, - { - id: 'trend-6', - updatedAt: new Date(), - user: { - name: '乐哥', - avatar: avatars2[5], - }, - group: { - name: '程序员日常', - link: 'http://github.com/', - }, - project: { - name: '品牌迭代', - link: 'http://github.com/', - }, - template: '在 @{group} 新建项目 @{project}', - }, -]; - -function getFakeCaptcha(req, res) { - return res.json('captcha-xxx'); -} - -export default { - 'GET /api/project/notice': getNotice, - 'GET /api/activities': getActivities, - 'POST /api/forms': (req, res) => { - res.send({ message: 'Ok' }); - }, - 'GET /api/tags': mockjs.mock({ - 'list|100': [{ name: '@city', 'value|1-100': 150, 'type|0-2': 1 }], - }), - 'GET /api/fake_list': getFakeList, - 'POST /api/fake_list': postFakeList, - 'GET /api/captcha': getFakeCaptcha, -}; diff --git a/mock/chart.js b/mock/chart.js deleted file mode 100644 index 65037758d3..0000000000 --- a/mock/chart.js +++ /dev/null @@ -1,196 +0,0 @@ -import moment from 'moment'; - -// mock data -const visitData = []; -const beginDay = new Date().getTime(); - -const fakeY = [7, 5, 4, 2, 4, 7, 5, 6, 5, 9, 6, 3, 1, 5, 3, 6, 5]; -for (let i = 0; i < fakeY.length; i += 1) { - visitData.push({ - x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'), - y: fakeY[i], - }); -} - -const visitData2 = []; -const fakeY2 = [1, 6, 4, 8, 3, 7, 2]; -for (let i = 0; i < fakeY2.length; i += 1) { - visitData2.push({ - x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'), - y: fakeY2[i], - }); -} - -const salesData = []; -for (let i = 0; i < 12; i += 1) { - salesData.push({ - x: `${i + 1}月`, - y: Math.floor(Math.random() * 1000) + 200, - }); -} -const searchData = []; -for (let i = 0; i < 50; i += 1) { - searchData.push({ - index: i + 1, - keyword: `搜索关键词-${i}`, - count: Math.floor(Math.random() * 1000), - range: Math.floor(Math.random() * 100), - status: Math.floor((Math.random() * 10) % 2), - }); -} -const salesTypeData = [ - { - x: '家用电器', - y: 4544, - }, - { - x: '食用酒水', - y: 3321, - }, - { - x: '个护健康', - y: 3113, - }, - { - x: '服饰箱包', - y: 2341, - }, - { - x: '母婴产品', - y: 1231, - }, - { - x: '其他', - y: 1231, - }, -]; - -const salesTypeDataOnline = [ - { - x: '家用电器', - y: 244, - }, - { - x: '食用酒水', - y: 321, - }, - { - x: '个护健康', - y: 311, - }, - { - x: '服饰箱包', - y: 41, - }, - { - x: '母婴产品', - y: 121, - }, - { - x: '其他', - y: 111, - }, -]; - -const salesTypeDataOffline = [ - { - x: '家用电器', - y: 99, - }, - { - x: '食用酒水', - y: 188, - }, - { - x: '个护健康', - y: 344, - }, - { - x: '服饰箱包', - y: 255, - }, - { - x: '其他', - y: 65, - }, -]; - -const offlineData = []; -for (let i = 0; i < 10; i += 1) { - offlineData.push({ - name: `Stores ${i}`, - cvr: Math.ceil(Math.random() * 9) / 10, - }); -} -const offlineChartData = []; -for (let i = 0; i < 20; i += 1) { - offlineChartData.push({ - x: new Date().getTime() + 1000 * 60 * 30 * i, - y1: Math.floor(Math.random() * 100) + 10, - y2: Math.floor(Math.random() * 100) + 10, - }); -} - -const radarOriginData = [ - { - name: '个人', - ref: 10, - koubei: 8, - output: 4, - contribute: 5, - hot: 7, - }, - { - name: '团队', - ref: 3, - koubei: 9, - output: 6, - contribute: 3, - hot: 1, - }, - { - name: '部门', - ref: 4, - koubei: 1, - output: 6, - contribute: 5, - hot: 7, - }, -]; - -const radarData = []; -const radarTitleMap = { - ref: '引用', - koubei: '口碑', - output: '产量', - contribute: '贡献', - hot: '热度', -}; -radarOriginData.forEach(item => { - Object.keys(item).forEach(key => { - if (key !== 'name') { - radarData.push({ - name: item.name, - label: radarTitleMap[key], - value: item[key], - }); - } - }); -}); - -const getFakeChartData = { - visitData, - visitData2, - salesData, - searchData, - offlineData, - offlineChartData, - salesTypeData, - salesTypeDataOnline, - salesTypeDataOffline, - radarData, -}; - -export default { - 'GET /api/fake_chart_data': getFakeChartData, -}; diff --git a/mock/geographic.js b/mock/geographic.js deleted file mode 100644 index e7772e8d32..0000000000 --- a/mock/geographic.js +++ /dev/null @@ -1,15 +0,0 @@ -import city from './geographic/city.json'; -import province from './geographic/province.json'; - -function getProvince(req, res) { - return res.json(province); -} - -function getCity(req, res) { - return res.json(city[req.params.province]); -} - -export default { - 'GET /api/geographic/province': getProvince, - 'GET /api/geographic/city/:province': getCity, -}; diff --git a/mock/geographic/city.json b/mock/geographic/city.json deleted file mode 100644 index 297837477a..0000000000 --- a/mock/geographic/city.json +++ /dev/null @@ -1,1784 +0,0 @@ -{ - "110000": [ - { - "province": "北京市", - "name": "市辖区", - "id": "110100" - } - ], - "120000": [ - { - "province": "天津市", - "name": "市辖区", - "id": "120100" - } - ], - "130000": [ - { - "province": "河北省", - "name": "石家庄市", - "id": "130100" - }, - { - "province": "河北省", - "name": "唐山市", - "id": "130200" - }, - { - "province": "河北省", - "name": "秦皇岛市", - "id": "130300" - }, - { - "province": "河北省", - "name": "邯郸市", - "id": "130400" - }, - { - "province": "河北省", - "name": "邢台市", - "id": "130500" - }, - { - "province": "河北省", - "name": "保定市", - "id": "130600" - }, - { - "province": "河北省", - "name": "张家口市", - "id": "130700" - }, - { - "province": "河北省", - "name": "承德市", - "id": "130800" - }, - { - "province": "河北省", - "name": "沧州市", - "id": "130900" - }, - { - "province": "河北省", - "name": "廊坊市", - "id": "131000" - }, - { - "province": "河北省", - "name": "衡水市", - "id": "131100" - }, - { - "province": "河北省", - "name": "省直辖县级行政区划", - "id": "139000" - } - ], - "140000": [ - { - "province": "山西省", - "name": "太原市", - "id": "140100" - }, - { - "province": "山西省", - "name": "大同市", - "id": "140200" - }, - { - "province": "山西省", - "name": "阳泉市", - "id": "140300" - }, - { - "province": "山西省", - "name": "长治市", - "id": "140400" - }, - { - "province": "山西省", - "name": "晋城市", - "id": "140500" - }, - { - "province": "山西省", - "name": "朔州市", - "id": "140600" - }, - { - "province": "山西省", - "name": "晋中市", - "id": "140700" - }, - { - "province": "山西省", - "name": "运城市", - "id": "140800" - }, - { - "province": "山西省", - "name": "忻州市", - "id": "140900" - }, - { - "province": "山西省", - "name": "临汾市", - "id": "141000" - }, - { - "province": "山西省", - "name": "吕梁市", - "id": "141100" - } - ], - "150000": [ - { - "province": "内蒙古自治区", - "name": "呼和浩特市", - "id": "150100" - }, - { - "province": "内蒙古自治区", - "name": "包头市", - "id": "150200" - }, - { - "province": "内蒙古自治区", - "name": "乌海市", - "id": "150300" - }, - { - "province": "内蒙古自治区", - "name": "赤峰市", - "id": "150400" - }, - { - "province": "内蒙古自治区", - "name": "通辽市", - "id": "150500" - }, - { - "province": "内蒙古自治区", - "name": "鄂尔多斯市", - "id": "150600" - }, - { - "province": "内蒙古自治区", - "name": "呼伦贝尔市", - "id": "150700" - }, - { - "province": "内蒙古自治区", - "name": "巴彦淖尔市", - "id": "150800" - }, - { - "province": "内蒙古自治区", - "name": "乌兰察布市", - "id": "150900" - }, - { - "province": "内蒙古自治区", - "name": "兴安盟", - "id": "152200" - }, - { - "province": "内蒙古自治区", - "name": "锡林郭勒盟", - "id": "152500" - }, - { - "province": "内蒙古自治区", - "name": "阿拉善盟", - "id": "152900" - } - ], - "210000": [ - { - "province": "辽宁省", - "name": "沈阳市", - "id": "210100" - }, - { - "province": "辽宁省", - "name": "大连市", - "id": "210200" - }, - { - "province": "辽宁省", - "name": "鞍山市", - "id": "210300" - }, - { - "province": "辽宁省", - "name": "抚顺市", - "id": "210400" - }, - { - "province": "辽宁省", - "name": "本溪市", - "id": "210500" - }, - { - "province": "辽宁省", - "name": "丹东市", - "id": "210600" - }, - { - "province": "辽宁省", - "name": "锦州市", - "id": "210700" - }, - { - "province": "辽宁省", - "name": "营口市", - "id": "210800" - }, - { - "province": "辽宁省", - "name": "阜新市", - "id": "210900" - }, - { - "province": "辽宁省", - "name": "辽阳市", - "id": "211000" - }, - { - "province": "辽宁省", - "name": "盘锦市", - "id": "211100" - }, - { - "province": "辽宁省", - "name": "铁岭市", - "id": "211200" - }, - { - "province": "辽宁省", - "name": "朝阳市", - "id": "211300" - }, - { - "province": "辽宁省", - "name": "葫芦岛市", - "id": "211400" - } - ], - "220000": [ - { - "province": "吉林省", - "name": "长春市", - "id": "220100" - }, - { - "province": "吉林省", - "name": "吉林市", - "id": "220200" - }, - { - "province": "吉林省", - "name": "四平市", - "id": "220300" - }, - { - "province": "吉林省", - "name": "辽源市", - "id": "220400" - }, - { - "province": "吉林省", - "name": "通化市", - "id": "220500" - }, - { - "province": "吉林省", - "name": "白山市", - "id": "220600" - }, - { - "province": "吉林省", - "name": "松原市", - "id": "220700" - }, - { - "province": "吉林省", - "name": "白城市", - "id": "220800" - }, - { - "province": "吉林省", - "name": "延边朝鲜族自治州", - "id": "222400" - } - ], - "230000": [ - { - "province": "黑龙江省", - "name": "哈尔滨市", - "id": "230100" - }, - { - "province": "黑龙江省", - "name": "齐齐哈尔市", - "id": "230200" - }, - { - "province": "黑龙江省", - "name": "鸡西市", - "id": "230300" - }, - { - "province": "黑龙江省", - "name": "鹤岗市", - "id": "230400" - }, - { - "province": "黑龙江省", - "name": "双鸭山市", - "id": "230500" - }, - { - "province": "黑龙江省", - "name": "大庆市", - "id": "230600" - }, - { - "province": "黑龙江省", - "name": "伊春市", - "id": "230700" - }, - { - "province": "黑龙江省", - "name": "佳木斯市", - "id": "230800" - }, - { - "province": "黑龙江省", - "name": "七台河市", - "id": "230900" - }, - { - "province": "黑龙江省", - "name": "牡丹江市", - "id": "231000" - }, - { - "province": "黑龙江省", - "name": "黑河市", - "id": "231100" - }, - { - "province": "黑龙江省", - "name": "绥化市", - "id": "231200" - }, - { - "province": "黑龙江省", - "name": "大兴安岭地区", - "id": "232700" - } - ], - "310000": [ - { - "province": "上海市", - "name": "市辖区", - "id": "310100" - } - ], - "320000": [ - { - "province": "江苏省", - "name": "南京市", - "id": "320100" - }, - { - "province": "江苏省", - "name": "无锡市", - "id": "320200" - }, - { - "province": "江苏省", - "name": "徐州市", - "id": "320300" - }, - { - "province": "江苏省", - "name": "常州市", - "id": "320400" - }, - { - "province": "江苏省", - "name": "苏州市", - "id": "320500" - }, - { - "province": "江苏省", - "name": "南通市", - "id": "320600" - }, - { - "province": "江苏省", - "name": "连云港市", - "id": "320700" - }, - { - "province": "江苏省", - "name": "淮安市", - "id": "320800" - }, - { - "province": "江苏省", - "name": "盐城市", - "id": "320900" - }, - { - "province": "江苏省", - "name": "扬州市", - "id": "321000" - }, - { - "province": "江苏省", - "name": "镇江市", - "id": "321100" - }, - { - "province": "江苏省", - "name": "泰州市", - "id": "321200" - }, - { - "province": "江苏省", - "name": "宿迁市", - "id": "321300" - } - ], - "330000": [ - { - "province": "浙江省", - "name": "杭州市", - "id": "330100" - }, - { - "province": "浙江省", - "name": "宁波市", - "id": "330200" - }, - { - "province": "浙江省", - "name": "温州市", - "id": "330300" - }, - { - "province": "浙江省", - "name": "嘉兴市", - "id": "330400" - }, - { - "province": "浙江省", - "name": "湖州市", - "id": "330500" - }, - { - "province": "浙江省", - "name": "绍兴市", - "id": "330600" - }, - { - "province": "浙江省", - "name": "金华市", - "id": "330700" - }, - { - "province": "浙江省", - "name": "衢州市", - "id": "330800" - }, - { - "province": "浙江省", - "name": "舟山市", - "id": "330900" - }, - { - "province": "浙江省", - "name": "台州市", - "id": "331000" - }, - { - "province": "浙江省", - "name": "丽水市", - "id": "331100" - } - ], - "340000": [ - { - "province": "安徽省", - "name": "合肥市", - "id": "340100" - }, - { - "province": "安徽省", - "name": "芜湖市", - "id": "340200" - }, - { - "province": "安徽省", - "name": "蚌埠市", - "id": "340300" - }, - { - "province": "安徽省", - "name": "淮南市", - "id": "340400" - }, - { - "province": "安徽省", - "name": "马鞍山市", - "id": "340500" - }, - { - "province": "安徽省", - "name": "淮北市", - "id": "340600" - }, - { - "province": "安徽省", - "name": "铜陵市", - "id": "340700" - }, - { - "province": "安徽省", - "name": "安庆市", - "id": "340800" - }, - { - "province": "安徽省", - "name": "黄山市", - "id": "341000" - }, - { - "province": "安徽省", - "name": "滁州市", - "id": "341100" - }, - { - "province": "安徽省", - "name": "阜阳市", - "id": "341200" - }, - { - "province": "安徽省", - "name": "宿州市", - "id": "341300" - }, - { - "province": "安徽省", - "name": "六安市", - "id": "341500" - }, - { - "province": "安徽省", - "name": "亳州市", - "id": "341600" - }, - { - "province": "安徽省", - "name": "池州市", - "id": "341700" - }, - { - "province": "安徽省", - "name": "宣城市", - "id": "341800" - } - ], - "350000": [ - { - "province": "福建省", - "name": "福州市", - "id": "350100" - }, - { - "province": "福建省", - "name": "厦门市", - "id": "350200" - }, - { - "province": "福建省", - "name": "莆田市", - "id": "350300" - }, - { - "province": "福建省", - "name": "三明市", - "id": "350400" - }, - { - "province": "福建省", - "name": "泉州市", - "id": "350500" - }, - { - "province": "福建省", - "name": "漳州市", - "id": "350600" - }, - { - "province": "福建省", - "name": "南平市", - "id": "350700" - }, - { - "province": "福建省", - "name": "龙岩市", - "id": "350800" - }, - { - "province": "福建省", - "name": "宁德市", - "id": "350900" - } - ], - "360000": [ - { - "province": "江西省", - "name": "南昌市", - "id": "360100" - }, - { - "province": "江西省", - "name": "景德镇市", - "id": "360200" - }, - { - "province": "江西省", - "name": "萍乡市", - "id": "360300" - }, - { - "province": "江西省", - "name": "九江市", - "id": "360400" - }, - { - "province": "江西省", - "name": "新余市", - "id": "360500" - }, - { - "province": "江西省", - "name": "鹰潭市", - "id": "360600" - }, - { - "province": "江西省", - "name": "赣州市", - "id": "360700" - }, - { - "province": "江西省", - "name": "吉安市", - "id": "360800" - }, - { - "province": "江西省", - "name": "宜春市", - "id": "360900" - }, - { - "province": "江西省", - "name": "抚州市", - "id": "361000" - }, - { - "province": "江西省", - "name": "上饶市", - "id": "361100" - } - ], - "370000": [ - { - "province": "山东省", - "name": "济南市", - "id": "370100" - }, - { - "province": "山东省", - "name": "青岛市", - "id": "370200" - }, - { - "province": "山东省", - "name": "淄博市", - "id": "370300" - }, - { - "province": "山东省", - "name": "枣庄市", - "id": "370400" - }, - { - "province": "山东省", - "name": "东营市", - "id": "370500" - }, - { - "province": "山东省", - "name": "烟台市", - "id": "370600" - }, - { - "province": "山东省", - "name": "潍坊市", - "id": "370700" - }, - { - "province": "山东省", - "name": "济宁市", - "id": "370800" - }, - { - "province": "山东省", - "name": "泰安市", - "id": "370900" - }, - { - "province": "山东省", - "name": "威海市", - "id": "371000" - }, - { - "province": "山东省", - "name": "日照市", - "id": "371100" - }, - { - "province": "山东省", - "name": "莱芜市", - "id": "371200" - }, - { - "province": "山东省", - "name": "临沂市", - "id": "371300" - }, - { - "province": "山东省", - "name": "德州市", - "id": "371400" - }, - { - "province": "山东省", - "name": "聊城市", - "id": "371500" - }, - { - "province": "山东省", - "name": "滨州市", - "id": "371600" - }, - { - "province": "山东省", - "name": "菏泽市", - "id": "371700" - } - ], - "410000": [ - { - "province": "河南省", - "name": "郑州市", - "id": "410100" - }, - { - "province": "河南省", - "name": "开封市", - "id": "410200" - }, - { - "province": "河南省", - "name": "洛阳市", - "id": "410300" - }, - { - "province": "河南省", - "name": "平顶山市", - "id": "410400" - }, - { - "province": "河南省", - "name": "安阳市", - "id": "410500" - }, - { - "province": "河南省", - "name": "鹤壁市", - "id": "410600" - }, - { - "province": "河南省", - "name": "新乡市", - "id": "410700" - }, - { - "province": "河南省", - "name": "焦作市", - "id": "410800" - }, - { - "province": "河南省", - "name": "濮阳市", - "id": "410900" - }, - { - "province": "河南省", - "name": "许昌市", - "id": "411000" - }, - { - "province": "河南省", - "name": "漯河市", - "id": "411100" - }, - { - "province": "河南省", - "name": "三门峡市", - "id": "411200" - }, - { - "province": "河南省", - "name": "南阳市", - "id": "411300" - }, - { - "province": "河南省", - "name": "商丘市", - "id": "411400" - }, - { - "province": "河南省", - "name": "信阳市", - "id": "411500" - }, - { - "province": "河南省", - "name": "周口市", - "id": "411600" - }, - { - "province": "河南省", - "name": "驻马店市", - "id": "411700" - }, - { - "province": "河南省", - "name": "省直辖县级行政区划", - "id": "419000" - } - ], - "420000": [ - { - "province": "湖北省", - "name": "武汉市", - "id": "420100" - }, - { - "province": "湖北省", - "name": "黄石市", - "id": "420200" - }, - { - "province": "湖北省", - "name": "十堰市", - "id": "420300" - }, - { - "province": "湖北省", - "name": "宜昌市", - "id": "420500" - }, - { - "province": "湖北省", - "name": "襄阳市", - "id": "420600" - }, - { - "province": "湖北省", - "name": "鄂州市", - "id": "420700" - }, - { - "province": "湖北省", - "name": "荆门市", - "id": "420800" - }, - { - "province": "湖北省", - "name": "孝感市", - "id": "420900" - }, - { - "province": "湖北省", - "name": "荆州市", - "id": "421000" - }, - { - "province": "湖北省", - "name": "黄冈市", - "id": "421100" - }, - { - "province": "湖北省", - "name": "咸宁市", - "id": "421200" - }, - { - "province": "湖北省", - "name": "随州市", - "id": "421300" - }, - { - "province": "湖北省", - "name": "恩施土家族苗族自治州", - "id": "422800" - }, - { - "province": "湖北省", - "name": "省直辖县级行政区划", - "id": "429000" - } - ], - "430000": [ - { - "province": "湖南省", - "name": "长沙市", - "id": "430100" - }, - { - "province": "湖南省", - "name": "株洲市", - "id": "430200" - }, - { - "province": "湖南省", - "name": "湘潭市", - "id": "430300" - }, - { - "province": "湖南省", - "name": "衡阳市", - "id": "430400" - }, - { - "province": "湖南省", - "name": "邵阳市", - "id": "430500" - }, - { - "province": "湖南省", - "name": "岳阳市", - "id": "430600" - }, - { - "province": "湖南省", - "name": "常德市", - "id": "430700" - }, - { - "province": "湖南省", - "name": "张家界市", - "id": "430800" - }, - { - "province": "湖南省", - "name": "益阳市", - "id": "430900" - }, - { - "province": "湖南省", - "name": "郴州市", - "id": "431000" - }, - { - "province": "湖南省", - "name": "永州市", - "id": "431100" - }, - { - "province": "湖南省", - "name": "怀化市", - "id": "431200" - }, - { - "province": "湖南省", - "name": "娄底市", - "id": "431300" - }, - { - "province": "湖南省", - "name": "湘西土家族苗族自治州", - "id": "433100" - } - ], - "440000": [ - { - "province": "广东省", - "name": "广州市", - "id": "440100" - }, - { - "province": "广东省", - "name": "韶关市", - "id": "440200" - }, - { - "province": "广东省", - "name": "深圳市", - "id": "440300" - }, - { - "province": "广东省", - "name": "珠海市", - "id": "440400" - }, - { - "province": "广东省", - "name": "汕头市", - "id": "440500" - }, - { - "province": "广东省", - "name": "佛山市", - "id": "440600" - }, - { - "province": "广东省", - "name": "江门市", - "id": "440700" - }, - { - "province": "广东省", - "name": "湛江市", - "id": "440800" - }, - { - "province": "广东省", - "name": "茂名市", - "id": "440900" - }, - { - "province": "广东省", - "name": "肇庆市", - "id": "441200" - }, - { - "province": "广东省", - "name": "惠州市", - "id": "441300" - }, - { - "province": "广东省", - "name": "梅州市", - "id": "441400" - }, - { - "province": "广东省", - "name": "汕尾市", - "id": "441500" - }, - { - "province": "广东省", - "name": "河源市", - "id": "441600" - }, - { - "province": "广东省", - "name": "阳江市", - "id": "441700" - }, - { - "province": "广东省", - "name": "清远市", - "id": "441800" - }, - { - "province": "广东省", - "name": "东莞市", - "id": "441900" - }, - { - "province": "广东省", - "name": "中山市", - "id": "442000" - }, - { - "province": "广东省", - "name": "潮州市", - "id": "445100" - }, - { - "province": "广东省", - "name": "揭阳市", - "id": "445200" - }, - { - "province": "广东省", - "name": "云浮市", - "id": "445300" - } - ], - "450000": [ - { - "province": "广西壮族自治区", - "name": "南宁市", - "id": "450100" - }, - { - "province": "广西壮族自治区", - "name": "柳州市", - "id": "450200" - }, - { - "province": "广西壮族自治区", - "name": "桂林市", - "id": "450300" - }, - { - "province": "广西壮族自治区", - "name": "梧州市", - "id": "450400" - }, - { - "province": "广西壮族自治区", - "name": "北海市", - "id": "450500" - }, - { - "province": "广西壮族自治区", - "name": "防城港市", - "id": "450600" - }, - { - "province": "广西壮族自治区", - "name": "钦州市", - "id": "450700" - }, - { - "province": "广西壮族自治区", - "name": "贵港市", - "id": "450800" - }, - { - "province": "广西壮族自治区", - "name": "玉林市", - "id": "450900" - }, - { - "province": "广西壮族自治区", - "name": "百色市", - "id": "451000" - }, - { - "province": "广西壮族自治区", - "name": "贺州市", - "id": "451100" - }, - { - "province": "广西壮族自治区", - "name": "河池市", - "id": "451200" - }, - { - "province": "广西壮族自治区", - "name": "来宾市", - "id": "451300" - }, - { - "province": "广西壮族自治区", - "name": "崇左市", - "id": "451400" - } - ], - "460000": [ - { - "province": "海南省", - "name": "海口市", - "id": "460100" - }, - { - "province": "海南省", - "name": "三亚市", - "id": "460200" - }, - { - "province": "海南省", - "name": "三沙市", - "id": "460300" - }, - { - "province": "海南省", - "name": "儋州市", - "id": "460400" - }, - { - "province": "海南省", - "name": "省直辖县级行政区划", - "id": "469000" - } - ], - "500000": [ - { - "province": "重庆市", - "name": "市辖区", - "id": "500100" - }, - { - "province": "重庆市", - "name": "县", - "id": "500200" - } - ], - "510000": [ - { - "province": "四川省", - "name": "成都市", - "id": "510100" - }, - { - "province": "四川省", - "name": "自贡市", - "id": "510300" - }, - { - "province": "四川省", - "name": "攀枝花市", - "id": "510400" - }, - { - "province": "四川省", - "name": "泸州市", - "id": "510500" - }, - { - "province": "四川省", - "name": "德阳市", - "id": "510600" - }, - { - "province": "四川省", - "name": "绵阳市", - "id": "510700" - }, - { - "province": "四川省", - "name": "广元市", - "id": "510800" - }, - { - "province": "四川省", - "name": "遂宁市", - "id": "510900" - }, - { - "province": "四川省", - "name": "内江市", - "id": "511000" - }, - { - "province": "四川省", - "name": "乐山市", - "id": "511100" - }, - { - "province": "四川省", - "name": "南充市", - "id": "511300" - }, - { - "province": "四川省", - "name": "眉山市", - "id": "511400" - }, - { - "province": "四川省", - "name": "宜宾市", - "id": "511500" - }, - { - "province": "四川省", - "name": "广安市", - "id": "511600" - }, - { - "province": "四川省", - "name": "达州市", - "id": "511700" - }, - { - "province": "四川省", - "name": "雅安市", - "id": "511800" - }, - { - "province": "四川省", - "name": "巴中市", - "id": "511900" - }, - { - "province": "四川省", - "name": "资阳市", - "id": "512000" - }, - { - "province": "四川省", - "name": "阿坝藏族羌族自治州", - "id": "513200" - }, - { - "province": "四川省", - "name": "甘孜藏族自治州", - "id": "513300" - }, - { - "province": "四川省", - "name": "凉山彝族自治州", - "id": "513400" - } - ], - "520000": [ - { - "province": "贵州省", - "name": "贵阳市", - "id": "520100" - }, - { - "province": "贵州省", - "name": "六盘水市", - "id": "520200" - }, - { - "province": "贵州省", - "name": "遵义市", - "id": "520300" - }, - { - "province": "贵州省", - "name": "安顺市", - "id": "520400" - }, - { - "province": "贵州省", - "name": "毕节市", - "id": "520500" - }, - { - "province": "贵州省", - "name": "铜仁市", - "id": "520600" - }, - { - "province": "贵州省", - "name": "黔西南布依族苗族自治州", - "id": "522300" - }, - { - "province": "贵州省", - "name": "黔东南苗族侗族自治州", - "id": "522600" - }, - { - "province": "贵州省", - "name": "黔南布依族苗族自治州", - "id": "522700" - } - ], - "530000": [ - { - "province": "云南省", - "name": "昆明市", - "id": "530100" - }, - { - "province": "云南省", - "name": "曲靖市", - "id": "530300" - }, - { - "province": "云南省", - "name": "玉溪市", - "id": "530400" - }, - { - "province": "云南省", - "name": "保山市", - "id": "530500" - }, - { - "province": "云南省", - "name": "昭通市", - "id": "530600" - }, - { - "province": "云南省", - "name": "丽江市", - "id": "530700" - }, - { - "province": "云南省", - "name": "普洱市", - "id": "530800" - }, - { - "province": "云南省", - "name": "临沧市", - "id": "530900" - }, - { - "province": "云南省", - "name": "楚雄彝族自治州", - "id": "532300" - }, - { - "province": "云南省", - "name": "红河哈尼族彝族自治州", - "id": "532500" - }, - { - "province": "云南省", - "name": "文山壮族苗族自治州", - "id": "532600" - }, - { - "province": "云南省", - "name": "西双版纳傣族自治州", - "id": "532800" - }, - { - "province": "云南省", - "name": "大理白族自治州", - "id": "532900" - }, - { - "province": "云南省", - "name": "德宏傣族景颇族自治州", - "id": "533100" - }, - { - "province": "云南省", - "name": "怒江傈僳族自治州", - "id": "533300" - }, - { - "province": "云南省", - "name": "迪庆藏族自治州", - "id": "533400" - } - ], - "540000": [ - { - "province": "西藏自治区", - "name": "拉萨市", - "id": "540100" - }, - { - "province": "西藏自治区", - "name": "日喀则市", - "id": "540200" - }, - { - "province": "西藏自治区", - "name": "昌都市", - "id": "540300" - }, - { - "province": "西藏自治区", - "name": "林芝市", - "id": "540400" - }, - { - "province": "西藏自治区", - "name": "山南市", - "id": "540500" - }, - { - "province": "西藏自治区", - "name": "那曲地区", - "id": "542400" - }, - { - "province": "西藏自治区", - "name": "阿里地区", - "id": "542500" - } - ], - "610000": [ - { - "province": "陕西省", - "name": "西安市", - "id": "610100" - }, - { - "province": "陕西省", - "name": "铜川市", - "id": "610200" - }, - { - "province": "陕西省", - "name": "宝鸡市", - "id": "610300" - }, - { - "province": "陕西省", - "name": "咸阳市", - "id": "610400" - }, - { - "province": "陕西省", - "name": "渭南市", - "id": "610500" - }, - { - "province": "陕西省", - "name": "延安市", - "id": "610600" - }, - { - "province": "陕西省", - "name": "汉中市", - "id": "610700" - }, - { - "province": "陕西省", - "name": "榆林市", - "id": "610800" - }, - { - "province": "陕西省", - "name": "安康市", - "id": "610900" - }, - { - "province": "陕西省", - "name": "商洛市", - "id": "611000" - } - ], - "620000": [ - { - "province": "甘肃省", - "name": "兰州市", - "id": "620100" - }, - { - "province": "甘肃省", - "name": "嘉峪关市", - "id": "620200" - }, - { - "province": "甘肃省", - "name": "金昌市", - "id": "620300" - }, - { - "province": "甘肃省", - "name": "白银市", - "id": "620400" - }, - { - "province": "甘肃省", - "name": "天水市", - "id": "620500" - }, - { - "province": "甘肃省", - "name": "武威市", - "id": "620600" - }, - { - "province": "甘肃省", - "name": "张掖市", - "id": "620700" - }, - { - "province": "甘肃省", - "name": "平凉市", - "id": "620800" - }, - { - "province": "甘肃省", - "name": "酒泉市", - "id": "620900" - }, - { - "province": "甘肃省", - "name": "庆阳市", - "id": "621000" - }, - { - "province": "甘肃省", - "name": "定西市", - "id": "621100" - }, - { - "province": "甘肃省", - "name": "陇南市", - "id": "621200" - }, - { - "province": "甘肃省", - "name": "临夏回族自治州", - "id": "622900" - }, - { - "province": "甘肃省", - "name": "甘南藏族自治州", - "id": "623000" - } - ], - "630000": [ - { - "province": "青海省", - "name": "西宁市", - "id": "630100" - }, - { - "province": "青海省", - "name": "海东市", - "id": "630200" - }, - { - "province": "青海省", - "name": "海北藏族自治州", - "id": "632200" - }, - { - "province": "青海省", - "name": "黄南藏族自治州", - "id": "632300" - }, - { - "province": "青海省", - "name": "海南藏族自治州", - "id": "632500" - }, - { - "province": "青海省", - "name": "果洛藏族自治州", - "id": "632600" - }, - { - "province": "青海省", - "name": "玉树藏族自治州", - "id": "632700" - }, - { - "province": "青海省", - "name": "海西蒙古族藏族自治州", - "id": "632800" - } - ], - "640000": [ - { - "province": "宁夏回族自治区", - "name": "银川市", - "id": "640100" - }, - { - "province": "宁夏回族自治区", - "name": "石嘴山市", - "id": "640200" - }, - { - "province": "宁夏回族自治区", - "name": "吴忠市", - "id": "640300" - }, - { - "province": "宁夏回族自治区", - "name": "固原市", - "id": "640400" - }, - { - "province": "宁夏回族自治区", - "name": "中卫市", - "id": "640500" - } - ], - "650000": [ - { - "province": "新疆维吾尔自治区", - "name": "乌鲁木齐市", - "id": "650100" - }, - { - "province": "新疆维吾尔自治区", - "name": "克拉玛依市", - "id": "650200" - }, - { - "province": "新疆维吾尔自治区", - "name": "吐鲁番市", - "id": "650400" - }, - { - "province": "新疆维吾尔自治区", - "name": "哈密市", - "id": "650500" - }, - { - "province": "新疆维吾尔自治区", - "name": "昌吉回族自治州", - "id": "652300" - }, - { - "province": "新疆维吾尔自治区", - "name": "博尔塔拉蒙古自治州", - "id": "652700" - }, - { - "province": "新疆维吾尔自治区", - "name": "巴音郭楞蒙古自治州", - "id": "652800" - }, - { - "province": "新疆维吾尔自治区", - "name": "阿克苏地区", - "id": "652900" - }, - { - "province": "新疆维吾尔自治区", - "name": "克孜勒苏柯尔克孜自治州", - "id": "653000" - }, - { - "province": "新疆维吾尔自治区", - "name": "喀什地区", - "id": "653100" - }, - { - "province": "新疆维吾尔自治区", - "name": "和田地区", - "id": "653200" - }, - { - "province": "新疆维吾尔自治区", - "name": "伊犁哈萨克自治州", - "id": "654000" - }, - { - "province": "新疆维吾尔自治区", - "name": "塔城地区", - "id": "654200" - }, - { - "province": "新疆维吾尔自治区", - "name": "阿勒泰地区", - "id": "654300" - }, - { - "province": "新疆维吾尔自治区", - "name": "自治区直辖县级行政区划", - "id": "659000" - } - ] -} diff --git a/mock/geographic/province.json b/mock/geographic/province.json deleted file mode 100644 index 910c83f08e..0000000000 --- a/mock/geographic/province.json +++ /dev/null @@ -1,138 +0,0 @@ -[ - { - "name": "北京市", - "id": "110000" - }, - { - "name": "天津市", - "id": "120000" - }, - { - "name": "河北省", - "id": "130000" - }, - { - "name": "山西省", - "id": "140000" - }, - { - "name": "内蒙古自治区", - "id": "150000" - }, - { - "name": "辽宁省", - "id": "210000" - }, - { - "name": "吉林省", - "id": "220000" - }, - { - "name": "黑龙江省", - "id": "230000" - }, - { - "name": "上海市", - "id": "310000" - }, - { - "name": "江苏省", - "id": "320000" - }, - { - "name": "浙江省", - "id": "330000" - }, - { - "name": "安徽省", - "id": "340000" - }, - { - "name": "福建省", - "id": "350000" - }, - { - "name": "江西省", - "id": "360000" - }, - { - "name": "山东省", - "id": "370000" - }, - { - "name": "河南省", - "id": "410000" - }, - { - "name": "湖北省", - "id": "420000" - }, - { - "name": "湖南省", - "id": "430000" - }, - { - "name": "广东省", - "id": "440000" - }, - { - "name": "广西壮族自治区", - "id": "450000" - }, - { - "name": "海南省", - "id": "460000" - }, - { - "name": "重庆市", - "id": "500000" - }, - { - "name": "四川省", - "id": "510000" - }, - { - "name": "贵州省", - "id": "520000" - }, - { - "name": "云南省", - "id": "530000" - }, - { - "name": "西藏自治区", - "id": "540000" - }, - { - "name": "陕西省", - "id": "610000" - }, - { - "name": "甘肃省", - "id": "620000" - }, - { - "name": "青海省", - "id": "630000" - }, - { - "name": "宁夏回族自治区", - "id": "640000" - }, - { - "name": "新疆维吾尔自治区", - "id": "650000" - }, - { - "name": "台湾省", - "id": "710000" - }, - { - "name": "香港特别行政区", - "id": "810000" - }, - { - "name": "澳门特别行政区", - "id": "820000" - } -] diff --git a/mock/notices.js b/mock/notices.ts similarity index 100% rename from mock/notices.js rename to mock/notices.ts diff --git a/mock/profile.js b/mock/profile.js deleted file mode 100644 index 228d686f38..0000000000 --- a/mock/profile.js +++ /dev/null @@ -1,177 +0,0 @@ -import mockjs from 'mockjs'; - -const basicGoods = [ - { - id: '1234561', - name: '矿泉水 550ml', - barcode: '12421432143214321', - price: '2.00', - num: '1', - amount: '2.00', - }, - { - id: '1234562', - name: '凉茶 300ml', - barcode: '12421432143214322', - price: '3.00', - num: '2', - amount: '6.00', - }, - { - id: '1234563', - name: '好吃的薯片', - barcode: '12421432143214323', - price: '7.00', - num: '4', - amount: '28.00', - }, - { - id: '1234564', - name: '特别好吃的蛋卷', - barcode: '12421432143214324', - price: '8.50', - num: '3', - amount: '25.50', - }, -]; - -const basicProgress = [ - { - key: '1', - time: '2017-10-01 14:10', - rate: '联系客户', - status: 'processing', - operator: '取货员 ID1234', - cost: '5mins', - }, - { - key: '2', - time: '2017-10-01 14:05', - rate: '取货员出发', - status: 'success', - operator: '取货员 ID1234', - cost: '1h', - }, - { - key: '3', - time: '2017-10-01 13:05', - rate: '取货员接单', - status: 'success', - operator: '取货员 ID1234', - cost: '5mins', - }, - { - key: '4', - time: '2017-10-01 13:00', - rate: '申请审批通过', - status: 'success', - operator: '系统', - cost: '1h', - }, - { - key: '5', - time: '2017-10-01 12:00', - rate: '发起退货申请', - status: 'success', - operator: '用户', - cost: '5mins', - }, -]; - -const advancedOperation1 = [ - { - key: 'op1', - type: '订购关系生效', - name: '曲丽丽', - status: 'agree', - updatedAt: '2017-10-03 19:23:12', - memo: '-', - }, - { - key: 'op2', - type: '财务复审', - name: '付小小', - status: 'reject', - updatedAt: '2017-10-03 19:23:12', - memo: '不通过原因', - }, - { - key: 'op3', - type: '部门初审', - name: '周毛毛', - status: 'agree', - updatedAt: '2017-10-03 19:23:12', - memo: '-', - }, - { - key: 'op4', - type: '提交订单', - name: '林东东', - status: 'agree', - updatedAt: '2017-10-03 19:23:12', - memo: '很棒', - }, - { - key: 'op5', - type: '创建订单', - name: '汗牙牙', - status: 'agree', - updatedAt: '2017-10-03 19:23:12', - memo: '-', - }, -]; - -const advancedOperation2 = [ - { - key: 'op1', - type: '订购关系生效', - name: '曲丽丽', - status: 'agree', - updatedAt: '2017-10-03 19:23:12', - memo: '-', - }, -]; - -const advancedOperation3 = [ - { - key: 'op1', - type: '创建订单', - name: '汗牙牙', - status: 'agree', - updatedAt: '2017-10-03 19:23:12', - memo: '-', - }, -]; -const getProfileAdvancedData = { - advancedOperation1, - advancedOperation2, - advancedOperation3, -}; - -const { Random } = mockjs; - -export default { - 'GET /api/profile/advanced': getProfileAdvancedData, - 'GET /api/profile/basic': (req, res) => { - const { id } = req.query; - const application = { - id, - status: '已取货', - orderNo: Random.id(), - childOrderNo: Random.id(), - }; - const userInfo = { - name: Random.cname(), - tel: '18100000000', - delivery: '菜鸟物流', - addr: '浙江省杭州市西湖区万塘路18号', - remark: '备注', - }; - res.json({ - userInfo, - application, - basicGoods, - basicProgress, - }); - }, -}; diff --git a/mock/route.ts b/mock/route.ts new file mode 100644 index 0000000000..418d10f1ab --- /dev/null +++ b/mock/route.ts @@ -0,0 +1,5 @@ +export default { + '/api/auth_routes': { + '/form/advanced-form': { authority: ['admin', 'user'] }, + }, +}; diff --git a/mock/rule.js b/mock/rule.js deleted file mode 100644 index 87d235b03e..0000000000 --- a/mock/rule.js +++ /dev/null @@ -1,131 +0,0 @@ -import { parse } from 'url'; - -// mock tableListDataSource -let tableListDataSource = []; -for (let i = 0; i < 46; i += 1) { - tableListDataSource.push({ - key: i, - disabled: i % 6 === 0, - href: 'https://ant.design', - avatar: [ - 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', - 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', - ][i % 2], - name: `TradeCode ${i}`, - title: `一个任务名称 ${i}`, - owner: '曲丽丽', - desc: '这是一段描述', - callNo: Math.floor(Math.random() * 1000), - status: Math.floor(Math.random() * 10) % 4, - updatedAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`), - createdAt: new Date(`2017-07-${Math.floor(i / 2) + 1}`), - progress: Math.ceil(Math.random() * 100), - }); -} - -function getRule(req, res, u) { - let url = u; - if (!url || Object.prototype.toString.call(url) !== '[object String]') { - url = req.url; // eslint-disable-line - } - - const params = parse(url, true).query; - - let dataSource = tableListDataSource; - - if (params.sorter) { - const s = params.sorter.split('_'); - dataSource = dataSource.sort((prev, next) => { - if (s[1] === 'descend') { - return next[s[0]] - prev[s[0]]; - } - return prev[s[0]] - next[s[0]]; - }); - } - - if (params.status) { - const status = params.status.split(','); - let filterDataSource = []; - status.forEach(s => { - filterDataSource = filterDataSource.concat( - dataSource.filter(data => parseInt(data.status, 10) === parseInt(s[0], 10)) - ); - }); - dataSource = filterDataSource; - } - - if (params.name) { - dataSource = dataSource.filter(data => data.name.indexOf(params.name) > -1); - } - - let pageSize = 10; - if (params.pageSize) { - pageSize = params.pageSize * 1; - } - - const result = { - list: dataSource, - pagination: { - total: dataSource.length, - pageSize, - current: parseInt(params.currentPage, 10) || 1, - }, - }; - - return res.json(result); -} - -function postRule(req, res, u, b) { - let url = u; - if (!url || Object.prototype.toString.call(url) !== '[object String]') { - url = req.url; // eslint-disable-line - } - - const body = (b && b.body) || req.body; - const { method, name, desc, key } = body; - - switch (method) { - /* eslint no-case-declarations:0 */ - case 'delete': - tableListDataSource = tableListDataSource.filter(item => key.indexOf(item.key) === -1); - break; - case 'post': - const i = Math.ceil(Math.random() * 10000); - tableListDataSource.unshift({ - key: i, - href: 'https://ant.design', - avatar: [ - 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', - 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', - ][i % 2], - name: `TradeCode ${i}`, - title: `一个任务名称 ${i}`, - owner: '曲丽丽', - desc, - callNo: Math.floor(Math.random() * 1000), - status: Math.floor(Math.random() * 10) % 2, - updatedAt: new Date(), - createdAt: new Date(), - progress: Math.ceil(Math.random() * 100), - }); - break; - case 'update': - tableListDataSource = tableListDataSource.map(item => { - if (item.key === key) { - Object.assign(item, { desc, name }); - return item; - } - return item; - }); - break; - default: - break; - } - - return getRule(req, res, u); -} - -export default { - 'GET /api/rule': getRule, - 'POST /api/rule': postRule, -}; diff --git a/mock/user.js b/mock/user.ts similarity index 100% rename from mock/user.js rename to mock/user.ts diff --git a/package.json b/package.json index 0704f91af2..e6eb407d48 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ant-design-pro", - "version": "2.3.1", + "version": "4.0.0", "private": true, "description": "An out-of-box UI solution for enterprise applications", "scripts": { @@ -13,23 +13,26 @@ "docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up", "docker:push": "npm run docker-hub:build && npm run docker:tag && docker push antdesign/ant-design-pro", "docker:tag": "docker tag ant-design-pro antdesign/ant-design-pro", - "functions:build": "npm run generateMock && netlify-lambda build ./lambda", - "functions:run": "npm run generateMock && cross-env NODE_ENV=dev netlify-lambda serve ./lambda", + "fetch:blocks": "node ./scripts/fetch-blocks.js", + "functions:build": "netlify-lambda build ./lambda", + "functions:run": "cross-env NODE_ENV=dev netlify-lambda serve ./lambda", "generateMock": "node ./scripts/generateMock", - "lint": "eslint --ext .js src mock tests && npm run lint:style && npm run lint:prettier", + "lint": "npm run lint:js && npm run lint:ts && npm run lint:style && npm run lint:prettier", "lint-staged": "lint-staged", "lint-staged:js": "eslint --ext .js", - "lint:fix": "eslint --fix --ext .js src mock tests && stylelint --fix 'src/**/*.less' --syntax less", + "lint-staged:ts": "tslint", + "lint:fix": "eslint --fix --ext .js src tests && npm run lint:style && npm run tslint:fix", + "lint:js": "eslint --ext .js src tests", "lint:prettier": "check-prettier lint", - "lint:style": "stylelint 'src/**/*.less' --syntax less", - "prettier": "node ./scripts/prettier.js", - "site": "umi build && npm run functions:build", + "lint:style": "stylelint --fix 'src/**/*.less' --syntax less", + "lint:ts": "tslint -p . -c tslint.yml", + "prettier": " check-prettier write", + "site": "npm run fetch:blocks && npm run functions:build && umi build", "start": "umi dev", "start:no-mock": "cross-env MOCK=none umi dev", "test": "umi test", "test:all": "node ./tests/run-tests.js", "test:component": "umi test ./src/components", - "tslint": "npm run tslint:fix", "tslint:fix": "tslint --fix 'src/**/*.ts*'" }, "husky": { @@ -40,10 +43,11 @@ "lint-staged": { "**/*.less": "stylelint --syntax less", "**/*.{js,jsx}": "npm run lint-staged:js", - "**/*.{js,ts,tsx,json,jsx,less}": [ - "node ./scripts/lint-prettier.js", + "**/*.{js,ts,tsx,md,json,jsx,less}": [ + "npm run prettier", "git add" - ] + ], + "**/*.{ts,tsx}": "npm run lint-staged:ts" }, "browserslist": [ "> 1%", @@ -51,42 +55,42 @@ "not ie <= 10" ], "dependencies": { + "@ant-design/pro-layout": "^4.2.0", "@antv/data-set": "^0.10.1", "antd": "^3.16.1", - "bizcharts": "^3.5.3-beta.0", - "bizcharts-plugin-slider": "^2.1.1-beta.1", "classnames": "^2.2.6", - "dva": "^2.4.1", - "enquire-js": "^0.2.1", - "express": "^4.16.4", - "gg-editor": "^2.0.2", - "lodash": "^4.17.11", - "lodash-decorators": "^6.0.1", + "dva": "^2.4.0", + "lodash": "^4.17.10", + "lodash-decorators": "^6.0.0", "memoize-one": "^5.0.0", - "moment": "^2.24.0", - "netlify-lambda": "^1.4.3", - "numeral": "^2.0.6", - "nzh": "^1.0.4", + "moment": "^2.22.2", "omit.js": "^1.0.0", - "path-to-regexp": "^3.0.0", - "prop-types": "^15.6.2", - "qs": "^6.6.0", - "rc-animate": "^2.6.0", - "react": "^16.7.0", + "path-to-regexp": "^2.4.0", + "prop-types": "^15.7.2", + "qs": "^6.7.0", + "rc-animate": "^2.4.4", + "react": "^16.8.5", "react-container-query": "^0.11.0", "react-copy-to-clipboard": "^5.0.1", "react-document-title": "^2.0.3", "react-dom": "^16.7.0", - "react-fittext": "^1.0.0", "react-media": "^1.9.2", - "resize-observer-polyfill": "^1.5.1", - "umi": "^2.4.4", - "umi-plugin-react": "^1.7.2", - "umi-request": "^1.0.5" + "react-media-hook2": "^1.0.2", + "umi": "^2.7.0-beta.2", + "umi-plugin-ga": "^1.1.3", + "umi-plugin-locale": "^2.8.0-beta.1", + "umi-plugin-pro-block": "^1.3.0", + "umi-plugin-react": "^1.8.0-beta.1", + "umi-request": "^1.0.7" }, "devDependencies": { + "@types/classnames": "^2.2.7", "@types/history": "^4.7.2", + "@types/jest": "^24.0.13", + "@types/lodash": "^4.14.123", + "@types/qs": "^6.5.3", "@types/react": "^16.8.1", + "@types/react-document-title": "^2.0.3", "@types/react-dom": "^16.0.11", "antd-pro-merge-less": "^1.0.0", "antd-theme-webpack-plugin": "^1.2.0", @@ -105,6 +109,7 @@ "eslint-plugin-jsx-a11y": "^6.2.1", "eslint-plugin-markdown": "^1.0.0", "eslint-plugin-react": "^7.12.4", + "express": "^4.16.4", "gh-pages": "^2.0.1", "husky": "^2.2.0", "jest-puppeteer": "^4.1.0", @@ -113,6 +118,8 @@ "lint-staged": "^8.1.1", "merge-umi-mock-data": "^1.0.4", "mockjs": "^1.0.1-beta3", + "netlify-lambda": "^1.4.3", + "node-fetch": "^2.6.0", "prettier": "^1.17.0", "serverless-http": "^2.0.1", "slash2": "^2.0.0", @@ -125,8 +132,8 @@ "stylelint-order": "^2.0.0", "tslint": "^5.12.1", "tslint-config-prettier": "^1.17.0", - "tslint-react": "^3.6.0", - "umi-plugin-ga": "^1.1.3" + "tslint-eslint-rules": "^5.4.0", + "tslint-react": "^3.6.0" }, "optionalDependencies": { "puppeteer": "^1.12.1" @@ -140,5 +147,33 @@ "src/**/*.less", "config/**/*.js*", "scripts/**/*.js" - ] + ], + "create-umi": { + "copy": [ + [ + "create-umi/README.md", + "README.md" + ], + [ + "create-umi/package.json", + "package.json" + ] + ], + "ignore": [ + ".dockerignore", + ".git", + ".gitpod.yml", + "CODE_OF_CONDUCT.md", + "Dockerfile", + "Dockerfile.*", + "lambda", + "LICENSE", + "netlify.toml", + "README.*.md", + "scripts", + "azure-pipelines.yml", + "docker", + "create-umi" + ] + } } diff --git a/scripts/fetch-blocks.js b/scripts/fetch-blocks.js new file mode 100644 index 0000000000..d6b27c1c51 --- /dev/null +++ b/scripts/fetch-blocks.js @@ -0,0 +1,129 @@ +const path = require('path'); +const fs = require('fs'); +const fetch = require('node-fetch'); +const exec = require('child_process').exec; +const getNewRouteCode = require('./repalceRouter'); +const router = require('./router.config'); +const chalk = require('chalk'); +const insertCode = require('./insertCode'); + +const fetchGithubFiles = async () => { + const ignoreFile = ['_scripts']; + const data = await fetch(`https://api.github.com/repos/ant-design/pro-blocks/git/trees/master`); + if (data.status !== 200) { + return; + } + const { tree } = await data.json(); + const files = tree.filter(file => file.type === 'tree' && !ignoreFile.includes(file.path)); + return Promise.resolve(files); +}; + +const relativePath = path.join(__dirname, '../config/config.ts'); + +const findAllInstallRouter = router => { + let routers = []; + router.forEach(item => { + if (item.component && item.path) { + if (item.path !== '/user' || item.path !== '/') { + routers.push({ + ...item, + routes: !!item.routes, + }); + } + } + if (item.routes) { + routers = routers.concat(findAllInstallRouter(item.routes)); + } + }); + return routers; +}; + +const filterParentRouter = (router, layout) => { + return [...router] + .map(item => { + if (item.routes && (!router.component || layout)) { + return { ...item, routes: filterParentRouter(item.routes, false) }; + } + if (item.redirect) { + return item; + } + return null; + }) + .filter(item => item); +}; +const firstUpperCase = pathString => { + return pathString + .replace('.', '') + .split(/\/|\-/) + .map(s => s.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase())) + .filter(s => s) + .join(''); +}; + +const execCmd = shell => { + return new Promise((resolve, reject) => { + exec(shell, { encoding: 'utf8' }, (error, statusbar) => { + if (error) { + console.log(error); + return reject(error); + } + console.log(statusbar); + resolve(); + }); + }); +}; + +// replace router config +const parentRouter = filterParentRouter(router, true); +const { routesPath, code } = getNewRouteCode(relativePath, parentRouter); +// write ParentRouter +fs.writeFileSync(routesPath, code); + +const installBlock = async () => { + let gitFiles = await fetchGithubFiles(); + const installRouters = findAllInstallRouter(router); + const installBlockIteration = async i => { + const item = installRouters[i]; + + if (!item || !item.path) { + return Promise.resolve(); + } + const gitPath = firstUpperCase(item.path); + // 如果这个区块在 git 上存在 + if (gitFiles.find(file => file.path === gitPath)) { + console.log('install ' + chalk.green(item.name) + ' to: ' + chalk.yellow(item.path)); + gitFiles = gitFiles.filter(file => file.path !== gitPath); + const skipModifyRouter = item.routes ? '--skip-modify-routes' : ''; + const cmd = `umi block add https://github.com/ant-design/pro-blocks/tree/master/${gitPath} --path=${ + item.path + } ${skipModifyRouter}`; + try { + await execCmd(cmd); + console.log(`install ${chalk.hex('#1890ff')(item.name)} success`); + } catch (error) { + console.error(error); + } + } + return installBlockIteration(i + 1); + }; + // 安装路由中设置的区块 + await installBlockIteration(0); + + const installGitFile = async i => { + const item = gitFiles[i]; + if (!item || !item.path) { + return Promise.resolve(); + } + console.log('install ' + chalk.green(item.path)); + const cmd = `umi block add https://github.com/ant-design/pro-blocks/tree/master/${item.path}`; + await execCmd(cmd); + return installBlockIteration(1); + }; + + // 安装 router 中没有的剩余区块. + installGitFile(0); +}; +installBlock().then(() => { + // 插入 pro 需要的演示代码 + insertCode(); +}); diff --git a/scripts/generateMock.js b/scripts/generateMock.js deleted file mode 100644 index e8600caf24..0000000000 --- a/scripts/generateMock.js +++ /dev/null @@ -1,3 +0,0 @@ -const generateMock = require('merge-umi-mock-data'); -const path = require('path'); -generateMock(path.join(__dirname, '../mock'), path.join(__dirname, '../lambda/mock/index.js')); diff --git a/scripts/getPrettierFiles.js b/scripts/getPrettierFiles.js deleted file mode 100644 index 500ab0926c..0000000000 --- a/scripts/getPrettierFiles.js +++ /dev/null @@ -1,23 +0,0 @@ -const glob = require('glob'); - -const getPrettierFiles = () => { - let files = []; - const jsFiles = glob.sync('src/**/*.js*', { ignore: ['**/node_modules/**', 'build/**'] }); - const tsFiles = glob.sync('src/**/*.ts*', { ignore: ['**/node_modules/**', 'build/**'] }); - const configFiles = glob.sync('config/**/*.js*', { ignore: ['**/node_modules/**', 'build/**'] }); - const scriptFiles = glob.sync('scripts/**/*.js'); - const lessFiles = glob.sync('src/**/*.less*', { ignore: ['**/node_modules/**', 'build/**'] }); - const mdFiles = glob.sync('src/**/*.md*', { ignore: ['**/node_modules/**', 'build/**'] }); - files = files.concat(jsFiles); - files = files.concat(tsFiles); - files = files.concat(configFiles); - files = files.concat(scriptFiles); - files = files.concat(lessFiles); - files = files.concat(mdFiles); - if (!files.length) { - return; - } - return files; -}; - -module.exports = getPrettierFiles; diff --git a/scripts/insertCode.js b/scripts/insertCode.js new file mode 100644 index 0000000000..d631dfa143 --- /dev/null +++ b/scripts/insertCode.js @@ -0,0 +1,161 @@ +const parser = require('@babel/parser'); +const traverse = require('@babel/traverse'); +const generate = require('@babel/generator'); +const t = require('@babel/types'); +const fs = require('fs'); +const path = require('path'); +const prettier = require('prettier'); +const chalk = require('chalk'); + +const parseCode = code => { + return parser.parse(code, { + sourceType: 'module', + plugins: ['typescript', 'jsx'], + }).program.body[0]; +}; + +/** + * 生成代码 + * @param {*} ast + */ +function generateCode(ast) { + const newCode = generate.default(ast, {}).code; + return prettier.format(newCode, { + // format same as ant-design-pro + singleQuote: true, + trailingComma: 'es5', + printWidth: 100, + parser: 'typescript', + }); +} + +const SettingCodeString = ` + + dispatch({ + type: 'settings/changeSetting', + payload: config, + }) + } + /> +`; + +const mapAst = (configPath, callBack) => { + const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), { + sourceType: 'module', + plugins: ['typescript', 'jsx'], + }); + // 查询当前配置文件是否导出 routes 属性 + traverse.default(ast, { + Program({ node }) { + const { body } = node; + callBack(body); + }, + }); + return generateCode(ast); +}; + +const insertBasicLayout = configPath => { + return mapAst(configPath, body => { + const index = body.findIndex(item => { + return item.type !== 'ImportDeclaration'; + }); + + body.forEach(item => { + // 从包中导出 SettingDrawer + if (item.type === 'ImportDeclaration') { + if (item.source.value === '@ant-design/pro-layout') { + item.specifiers.push(parseCode(`SettingDrawer`).expression); + } + } + if (item.type === 'VariableDeclaration') { + const { + id, + init: { body }, + } = item.declarations[0]; + // 给 BasicLayout 中插入 button 和 设置抽屉 + if (id.name === `BasicLayout`) { + body.body.forEach(node => { + if (node.type === 'ReturnStatement') { + const JSXFragment = parseCode(`<>`).expression; + JSXFragment.children.push({ ...node.argument }); + JSXFragment.children.push(parseCode(SettingCodeString).expression); + node.argument = JSXFragment; + } + }); + } + } + }); + }); +}; + +const insertBlankLayout = configPath => { + return mapAst(configPath, body => { + const index = body.findIndex(item => { + return item.type !== 'ImportDeclaration'; + }); + // 从组件中导入 CopyBlock + body.splice( + index, + 0, + parseCode(`import CopyBlock from '@/components/CopyBlock'; + `), + ); + body.forEach(item => { + if (item.type === 'VariableDeclaration') { + const { id, init } = item.declarations[0]; + // 给 BasicLayout 中插入 button 和 设置抽屉 + if (id.name === `Layout`) { + const JSXFragment = parseCode(`<>`).expression; + JSXFragment.children.push({ ...init.body }); + JSXFragment.children.push(parseCode(` `).expression); + init.body = JSXFragment; + } + } + }); + }); +}; + +const insertRightContent = configPath => { + return mapAst(configPath, body => { + const index = body.findIndex(item => { + return item.type !== 'ImportDeclaration'; + }); + // 从组件中导入 CopyBlock + body.splice(index, 0, parseCode(`import NoticeIconView from './NoticeIconView';`)); + + body.forEach(item => { + if (item.type === 'ClassDeclaration') { + const classBody = item.body.body[0].body; + classBody.body.forEach(node => { + if (node.type === 'ReturnStatement') { + const index = node.argument.children.findIndex(item => { + if (item.type === 'JSXElement') { + if (item.openingElement.name.name === 'Avatar') { + return true; + } + } + }); + node.argument.children.splice(index, 1, parseCode(``).expression); + node.argument.children.splice(index, 0, parseCode(``).expression); + } + }); + } + }); + }); +}; + +module.exports = () => { + const basicLayoutPath = path.join(__dirname, '../src/layouts/BasicLayout.tsx'); + fs.writeFileSync(basicLayoutPath, insertBasicLayout(basicLayoutPath)); + console.log(`insert ${chalk.hex('#1890ff')('BasicLayout')} success`); + + const rightContentPath = path.join(__dirname, '../src/components/GlobalHeader/RightContent.tsx'); + fs.writeFileSync(rightContentPath, insertRightContent(rightContentPath)); + console.log(`insert ${chalk.hex('#1890ff')('RightContent')} success`); + + const blankLayoutPath = path.join(__dirname, '../src/layouts/BlankLayout.tsx'); + fs.writeFileSync(blankLayoutPath, insertBlankLayout(blankLayoutPath)); + console.log(`insert ${chalk.hex('#1890ff')('blankLayoutPath')} success`); +}; diff --git a/scripts/lint-prettier.js b/scripts/lint-prettier.js deleted file mode 100644 index 677f793bee..0000000000 --- a/scripts/lint-prettier.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * copy to https://github.com/facebook/react/blob/master/scripts/prettier/index.js - * prettier api doc https://prettier.io/docs/en/api.html - *----------*****-------------- - * lint file is prettier - *----------*****-------------- - */ - -const prettier = require('prettier'); -const fs = require('fs'); -const chalk = require('chalk'); -const prettierConfigPath = require.resolve('../.prettierrc'); - -const files = process.argv.slice(2); - -let didError = false; - -files.forEach(file => { - Promise.all([ - prettier.resolveConfig(file, { - config: prettierConfigPath, - }), - prettier.getFileInfo(file), - ]) - .then(resolves => { - const [options, fileInfo] = resolves; - if (fileInfo.ignored) { - return; - } - const input = fs.readFileSync(file, 'utf8'); - const withParserOptions = { - ...options, - parser: fileInfo.inferredParser, - }; - const output = prettier.format(input, withParserOptions); - if (output !== input) { - fs.writeFileSync(file, output, 'utf8'); - console.log(chalk.green(`${file} is prettier`)); - } - }) - .catch(e => { - didError = true; - }) - .finally(() => { - if (didError) { - process.exit(1); - } - console.log(chalk.hex('#1890FF')('prettier success!')); - }); -}); diff --git a/scripts/prettier.js b/scripts/prettier.js deleted file mode 100644 index 17ded6c500..0000000000 --- a/scripts/prettier.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * copy to https://github.com/facebook/react/blob/master/scripts/prettier/index.js - * prettier api doc https://prettier.io/docs/en/api.html - *----------*****-------------- - * prettier all js and all ts. - *----------*****-------------- - */ - -const prettier = require('prettier'); -const fs = require('fs'); -const getPrettierFiles = require('./getPrettierFiles'); -const prettierConfigPath = require.resolve('../.prettierrc'); -const chalk = require('chalk'); - -let didError = false; - -const files = getPrettierFiles(); - -files.forEach(file => { - const options = prettier.resolveConfig.sync(file, { - config: prettierConfigPath, - }); - const fileInfo = prettier.getFileInfo.sync(file); - if (fileInfo.ignored) { - return; - } - try { - const input = fs.readFileSync(file, 'utf8'); - const withParserOptions = { - ...options, - parser: fileInfo.inferredParser, - }; - const output = prettier.format(input, withParserOptions); - if (output !== input) { - fs.writeFileSync(file, output, 'utf8'); - console.log(chalk.green(`${file} is prettier`)); - } - } catch (e) { - didError = true; - } -}); - -if (didError) { - process.exit(1); -} -console.log(chalk.hex('#1890FF')('prettier success!')); diff --git a/scripts/repalceRouter.js b/scripts/repalceRouter.js new file mode 100644 index 0000000000..4bb3c4f45c --- /dev/null +++ b/scripts/repalceRouter.js @@ -0,0 +1,77 @@ +const parser = require('@babel/parser'); +const traverse = require('@babel/traverse'); +const generate = require('@babel/generator'); +const t = require('@babel/types'); +const fs = require('fs'); +const prettier = require('prettier'); + +const getNewRouteCode = (configPath, newRoute) => { + const ast = parser.parse(fs.readFileSync(configPath, 'utf-8'), { + sourceType: 'module', + plugins: ['typescript'], + }); + let routesNode = null; + const importModules = []; + // 查询当前配置文件是否导出 routes 属性 + traverse.default(ast, { + Program({ node }) { + // find import + const { body } = node; + body.forEach(item => { + if (t.isImportDeclaration(item)) { + const { specifiers } = item; + const defaultEpecifier = specifiers.find(s => { + return t.isImportDefaultSpecifier(s) && t.isIdentifier(s.local); + }); + if (defaultEpecifier && t.isStringLiteral(item.source)) { + importModules.push({ + identifierName: defaultEpecifier.local.name, + modulePath: item.source.value, + }); + } + } + }); + }, + ObjectExpression({ node, parent }) { + // find routes on object, like { routes: [] } + if (t.isArrayExpression(parent)) { + // children routes + return; + } + const { properties } = node; + properties.forEach(p => { + const { key, value } = p; + if (t.isObjectProperty(p) && t.isIdentifier(key) && key.name === 'routes') { + if (value) { + // find json file program expression + (p.value = parser.parse(JSON.stringify(newRoute)).program.body[0].expression), + (routesNode = value); + } + } + }); + }, + }); + if (routesNode) { + const code = generateCode(ast); + return { code, routesPath: configPath }; + } else { + throw new Error('route array config not found.'); + } +}; + +/** + * 生成代码 + * @param {*} ast + */ +function generateCode(ast) { + const newCode = generate.default(ast, {}).code; + return prettier.format(newCode, { + // format same as ant-design-pro + singleQuote: true, + trailingComma: 'es5', + printWidth: 100, + parser: 'typescript', + }); +} + +module.exports = getNewRouteCode; diff --git a/scripts/router.config.js b/scripts/router.config.js new file mode 100644 index 0000000000..38a90a1b9d --- /dev/null +++ b/scripts/router.config.js @@ -0,0 +1,236 @@ +module.exports = [ + { + path: '/', + component: '../layouts/BlankLayout', + routes: [ + // user + { + path: '/user', + component: '../layouts/UserLayout', + routes: [ + { path: '/user/login', name: 'login', component: './User/Login' }, + { path: '/user/register', name: 'register', component: './User/Register' }, + { + path: '/user/register-result', + name: 'register.result', + component: './User/RegisterResult', + }, + { path: '/user', redirect: '/user/login' }, + { + component: '404', + }, + ], + }, + // app + { + path: '/', + component: '../layouts/BasicLayout', + Routes: ['src/pages/Authorized'], + authority: ['admin', 'user'], + routes: [ + // dashboard + { + path: '/dashboard', + name: 'dashboard', + icon: 'dashboard', + routes: [ + { + path: '/dashboard/analysis', + name: 'analysis', + component: './Dashboard/Analysis', + }, + { + path: '/dashboard/monitor', + name: 'monitor', + component: './Dashboard/Monitor', + }, + { + path: '/dashboard/workplace', + name: 'workplace', + component: './Dashboard/Workplace', + }, + ], + }, + // forms + { + path: '/form', + icon: 'form', + name: 'form', + routes: [ + { + path: '/form/basic-form', + name: 'basicform', + component: './Form/BasicForm', + }, + { + path: '/form/step-form', + name: 'stepform', + component: './Form/StepForm', + }, + { + path: '/form/advanced-form', + name: 'advancedform', + authority: ['admin'], + component: './Form/AdvancedForm', + }, + ], + }, + // list + { + path: '/list', + icon: 'table', + name: 'list', + routes: [ + { + path: '/list/table-list', + name: 'searchtable', + component: './list/Tablelist', + }, + { + path: '/list/basic-list', + name: 'basiclist', + component: './list/Basiclist', + }, + { + path: '/list/card-list', + name: 'cardlist', + component: './list/Cardlist', + }, + { + path: '/list/search', + name: 'search-list', + component: './list/search', + routes: [ + { + path: '/list/search/articles', + name: 'articles', + component: './list/Articles', + }, + { + path: '/list/search/projects', + name: 'projects', + component: './list/Projects', + }, + { + path: '/list/search/applications', + name: 'applications', + component: './list/Applications', + }, + { + path: '/list/search', + redirect: '/list/search/articles', + }, + ], + }, + ], + }, + { + path: '/profile', + name: 'profile', + icon: 'profile', + routes: [ + // profile + { + path: '/profile/basic', + name: 'basic', + component: './Profile/BasicProfile', + }, + { + path: '/profile/basic/:id', + hideInMenu: true, + component: './Profile/BasicProfile', + }, + { + path: '/profile/advanced', + name: 'advanced', + authority: ['admin'], + component: './Profile/AdvancedProfile', + }, + ], + }, + { + name: 'result', + icon: 'check-circle-o', + path: '/result', + routes: [ + // result + { + path: '/result/success', + name: 'success', + component: './Result/Success', + }, + { path: '/result/fail', name: 'fail', component: './Result/Error' }, + ], + }, + { + name: 'exception', + icon: 'warning', + path: '/exception', + routes: [ + // exception + { + path: '/exception/403', + name: 'not-permission', + component: './Exception/403', + }, + { + path: '/exception/404', + name: 'not-find', + component: './Exception/404', + }, + { + path: '/exception/500', + name: 'server-error', + component: './Exception/500', + }, + ], + }, + { + name: 'account', + icon: 'user', + path: '/account', + routes: [ + { + path: '/account/center', + name: 'center', + component: './Account/Center/Center', + }, + { + path: '/account/settings', + name: 'settings', + component: './Account/Settings/Info', + }, + ], + }, + // editor + { + name: 'editor', + icon: 'highlight', + path: '/editor', + routes: [ + { + path: '/editor/flow', + name: 'flow', + component: './Editor/GGEditor/Flow', + }, + { + path: '/editor/mind', + name: 'mind', + component: './Editor/GGEditor/Mind', + }, + { + path: '/editor/koni', + name: 'koni', + component: './Editor/GGEditor/Koni', + }, + ], + }, + { path: '/', redirect: '/dashboard/analysis', authority: ['admin', 'user'] }, + { + component: '404', + }, + ], + }, + ], + }, +]; diff --git a/src/app.js b/src/app.js deleted file mode 100644 index 2e98b22be0..0000000000 --- a/src/app.js +++ /dev/null @@ -1,11 +0,0 @@ -export const dva = { - config: { - onError(err) { - err.preventDefault(); - }, - }, -}; - -export function render(oldRender) { - oldRender(); -} diff --git a/src/components/ActiveChart/index.js b/src/components/ActiveChart/index.js deleted file mode 100644 index a7bf0bfc78..0000000000 --- a/src/components/ActiveChart/index.js +++ /dev/null @@ -1,98 +0,0 @@ -import React, { Component } from 'react'; -import { MiniArea } from '../Charts'; -import NumberInfo from '../NumberInfo'; -import styles from './index.less'; - -function fixedZero(val) { - return val * 1 < 10 ? `0${val}` : val; -} - -function getActiveData() { - const activeData = []; - for (let i = 0; i < 24; i += 1) { - activeData.push({ - x: `${fixedZero(i)}:00`, - y: Math.floor(Math.random() * 200) + i * 50, - }); - } - return activeData; -} - -export default class ActiveChart extends Component { - state = { - activeData: getActiveData(), - }; - - componentDidMount() { - this.loopData(); - } - - componentWillUnmount() { - clearTimeout(this.timer); - cancelAnimationFrame(this.requestRef); - } - - loopData = () => { - this.timer = setTimeout(() => { - this.setState( - { - activeData: getActiveData(), - }, - () => { - this.loopData(); - } - ); - }, 500); - }; - - render() { - const { activeData = [] } = this.state; - - return ( -
- -
- -
- {activeData && ( -
-
-

{[...activeData].sort()[activeData.length - 1].y + 200} 亿元

-

{[...activeData].sort()[Math.floor(activeData.length / 2)].y} 亿元

-
-
-
-
-
-
-
-
- )} - {activeData && ( -
- 00:00 - {activeData[Math.floor(activeData.length / 2)].x} - {activeData[activeData.length - 1].x} -
- )} -
- ); - } -} diff --git a/src/components/ActiveChart/index.less b/src/components/ActiveChart/index.less deleted file mode 100644 index 2f5d15f2ba..0000000000 --- a/src/components/ActiveChart/index.less +++ /dev/null @@ -1,51 +0,0 @@ -.activeChart { - position: relative; -} -.activeChartGrid { - p { - position: absolute; - top: 80px; - } - p:last-child { - top: 115px; - } -} -.activeChartLegend { - position: relative; - height: 20px; - margin-top: 8px; - font-size: 0; - line-height: 20px; - span { - display: inline-block; - width: 33.33%; - font-size: 12px; - text-align: center; - } - span:first-child { - text-align: left; - } - span:last-child { - text-align: right; - } -} -.dashedLine { - position: relative; - top: -70px; - left: -3px; - height: 1px; - - .line { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-image: linear-gradient(to right, transparent 50%, #e9e9e9 50%); - background-size: 6px; - } -} - -.dashedLine:last-child { - top: -36px; -} diff --git a/src/components/ArticleListContent/index.d.ts b/src/components/ArticleListContent/index.d.ts deleted file mode 100644 index bb4988a96d..0000000000 --- a/src/components/ArticleListContent/index.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; - -export interface ApplicationsProps { - data: { - content?: string; - updatedAt?: any; - avatar?: string; - owner?: string; - href?: string; - }; -} - -export default class ArticleListContent extends React.Component {} diff --git a/src/components/ArticleListContent/index.js b/src/components/ArticleListContent/index.js deleted file mode 100644 index c4525d6a51..0000000000 --- a/src/components/ArticleListContent/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import moment from 'moment'; -import { Avatar } from 'antd'; -import styles from './index.less'; - -const ArticleListContent = ({ data: { content, updatedAt, avatar, owner, href } }) => ( -
-
{content}
-
- - {owner} 发布在 {href} - {moment(updatedAt).format('YYYY-MM-DD HH:mm')} -
-
-); - -export default ArticleListContent; diff --git a/src/components/ArticleListContent/index.less b/src/components/ArticleListContent/index.less deleted file mode 100644 index dd0baa101d..0000000000 --- a/src/components/ArticleListContent/index.less +++ /dev/null @@ -1,38 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.listContent { - .description { - max-width: 720px; - line-height: 22px; - } - .extra { - margin-top: 16px; - color: @text-color-secondary; - line-height: 22px; - & > :global(.ant-avatar) { - position: relative; - top: 1px; - width: 20px; - height: 20px; - margin-right: 8px; - vertical-align: top; - } - & > em { - margin-left: 16px; - color: @disabled-color; - font-style: normal; - } - } -} - -@media screen and (max-width: @screen-xs) { - .listContent { - .extra { - & > em { - display: block; - margin-top: 8px; - margin-left: 0; - } - } - } -} diff --git a/src/components/Authorized/Authorized.js b/src/components/Authorized/Authorized.js deleted file mode 100644 index 75d57b88c2..0000000000 --- a/src/components/Authorized/Authorized.js +++ /dev/null @@ -1,8 +0,0 @@ -import CheckPermissions from './CheckPermissions'; - -const Authorized = ({ children, authority, noMatch = null }) => { - const childrenRender = typeof children === 'undefined' ? null : children; - return CheckPermissions(authority, childrenRender, noMatch); -}; - -export default Authorized; diff --git a/src/components/Authorized/Authorized.tsx b/src/components/Authorized/Authorized.tsx new file mode 100644 index 0000000000..a8bbb5e049 --- /dev/null +++ b/src/components/Authorized/Authorized.tsx @@ -0,0 +1,29 @@ +import CheckPermissions from './CheckPermissions'; +import { IAuthorityType } from './CheckPermissions'; +import Secured from './Secured'; +import check from './CheckPermissions'; +import AuthorizedRoute from './AuthorizedRoute'; +import React from 'react'; + +interface IAuthorizedProps { + authority: IAuthorityType; + noMatch?: React.ReactNode; +} + +type IAuthorizedType = React.FunctionComponent & { + Secured: typeof Secured; + check: typeof check; + AuthorizedRoute: typeof AuthorizedRoute; +}; + +const Authorized: React.FunctionComponent = ({ + children, + authority, + noMatch = null, +}) => { + const childrenRender: React.ReactNode = typeof children === 'undefined' ? null : children; + const dom = CheckPermissions(authority, childrenRender, noMatch); + return <>{dom}; +}; + +export default Authorized as IAuthorizedType; diff --git a/src/components/Authorized/AuthorizedRoute.d.ts b/src/components/Authorized/AuthorizedRoute.d.ts deleted file mode 100644 index f94427dadd..0000000000 --- a/src/components/Authorized/AuthorizedRoute.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import { RouteProps } from 'react-router'; - -type authorityFN = (currentAuthority?: string) => boolean; - -type authority = string | string[] | authorityFN | Promise; - -export interface IAuthorizedRouteProps extends RouteProps { - authority: authority; -} -export { authority }; - -export default class AuthorizedRoute extends React.Component {} diff --git a/src/components/Authorized/AuthorizedRoute.js b/src/components/Authorized/AuthorizedRoute.js deleted file mode 100644 index a622ed381a..0000000000 --- a/src/components/Authorized/AuthorizedRoute.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { Route, Redirect } from 'umi'; -import Authorized from './Authorized'; - -// TODO: umi只会返回render和rest -const AuthorizedRoute = ({ component: Component, render, authority, redirectPath, ...rest }) => ( - } />} - > - (Component ? : render(props))} /> - -); - -export default AuthorizedRoute; diff --git a/src/components/Authorized/AuthorizedRoute.tsx b/src/components/Authorized/AuthorizedRoute.tsx new file mode 100644 index 0000000000..7ff18c5500 --- /dev/null +++ b/src/components/Authorized/AuthorizedRoute.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Route, Redirect } from 'umi'; +import Authorized from './Authorized'; +import { IAuthorityType } from './CheckPermissions'; + +interface IAuthorizedRoutePops { + currentAuthority: string; + component: React.ComponentClass; + render: (props: any) => React.ReactNode; + redirectPath: string; + authority: IAuthorityType; +} + +const AuthorizedRoute: React.SFC = ({ + component: Component, + render, + authority, + redirectPath, + ...rest +}) => ( + } />} + > + (Component ? : render(props))} + /> + +); + +export default AuthorizedRoute; diff --git a/src/components/Authorized/CheckPermissions.test.js b/src/components/Authorized/CheckPermissions.test.js deleted file mode 100644 index 3988d85a18..0000000000 --- a/src/components/Authorized/CheckPermissions.test.js +++ /dev/null @@ -1,55 +0,0 @@ -import { checkPermissions } from './CheckPermissions'; - -const target = 'ok'; -const error = 'error'; - -describe('test CheckPermissions', () => { - it('Correct string permission authentication', () => { - expect(checkPermissions('user', 'user', target, error)).toEqual('ok'); - }); - it('Correct string permission authentication', () => { - expect(checkPermissions('user', 'NULL', target, error)).toEqual('error'); - }); - it('authority is undefined , return ok', () => { - expect(checkPermissions(null, 'NULL', target, error)).toEqual('ok'); - }); - it('currentAuthority is undefined , return error', () => { - expect(checkPermissions('admin', null, target, error)).toEqual('error'); - }); - it('Wrong string permission authentication', () => { - expect(checkPermissions('admin', 'user', target, error)).toEqual('error'); - }); - it('Correct Array permission authentication', () => { - expect(checkPermissions(['user', 'admin'], 'user', target, error)).toEqual('ok'); - }); - it('Wrong Array permission authentication,currentAuthority error', () => { - expect(checkPermissions(['user', 'admin'], 'user,admin', target, error)).toEqual('error'); - }); - it('Wrong Array permission authentication', () => { - expect(checkPermissions(['user', 'admin'], 'guest', target, error)).toEqual('error'); - }); - it('Wrong Function permission authentication', () => { - expect(checkPermissions(() => false, 'guest', target, error)).toEqual('error'); - }); - it('Correct Function permission authentication', () => { - expect(checkPermissions(() => true, 'guest', target, error)).toEqual('ok'); - }); - it('authority is string, currentAuthority is array, return ok', () => { - expect(checkPermissions('user', ['user'], target, error)).toEqual('ok'); - }); - it('authority is string, currentAuthority is array, return ok', () => { - expect(checkPermissions('user', ['user', 'admin'], target, error)).toEqual('ok'); - }); - it('authority is array, currentAuthority is array, return ok', () => { - expect(checkPermissions(['user', 'admin'], ['user', 'admin'], target, error)).toEqual('ok'); - }); - it('Wrong Function permission authentication', () => { - expect(checkPermissions(() => false, ['user'], target, error)).toEqual('error'); - }); - it('Correct Function permission authentication', () => { - expect(checkPermissions(() => true, ['user'], target, error)).toEqual('ok'); - }); - it('authority is undefined , return ok', () => { - expect(checkPermissions(null, ['user'], target, error)).toEqual('ok'); - }); -}); diff --git a/src/components/Authorized/CheckPermissions.js b/src/components/Authorized/CheckPermissions.tsx similarity index 72% rename from src/components/Authorized/CheckPermissions.js rename to src/components/Authorized/CheckPermissions.tsx index a1da261811..1d599e37bd 100644 --- a/src/components/Authorized/CheckPermissions.js +++ b/src/components/Authorized/CheckPermissions.tsx @@ -3,6 +3,13 @@ import React from 'react'; import PromiseRender from './PromiseRender'; import { CURRENT } from './renderAuthorize'; +export type IAuthorityType = + | undefined + | string + | string[] + | Promise + | ((currentAuthority: string | string[]) => IAuthorityType); + /** * 通用权限检查方法 * Common check permissions method @@ -11,7 +18,12 @@ import { CURRENT } from './renderAuthorize'; * @param { 通过的组件 | Passing components } target * @param { 未通过的组件 | no pass components } Exception */ -const checkPermissions = (authority, currentAuthority, target, Exception) => { +const checkPermissions = ( + authority: IAuthorityType, + currentAuthority: string | string[], + target: T, + Exception: K, +): T | K | React.ReactNode => { // 没有判定权限.默认查看所有 // Retirement authority, return target; if (!authority) { @@ -41,7 +53,7 @@ const checkPermissions = (authority, currentAuthority, target, Exception) => { } // Promise 处理 if (authority instanceof Promise) { - return ; + return ok={target} error={Exception} promise={authority} />; } // Function 处理 if (typeof authority === 'function') { @@ -49,7 +61,7 @@ const checkPermissions = (authority, currentAuthority, target, Exception) => { const bool = authority(currentAuthority); // 函数执行后返回值是 Promise if (bool instanceof Promise) { - return ; + return ok={target} error={Exception} promise={bool} />; } if (bool) { return target; @@ -64,7 +76,8 @@ const checkPermissions = (authority, currentAuthority, target, Exception) => { export { checkPermissions }; -const check = (authority, target, Exception) => - checkPermissions(authority, CURRENT, target, Exception); +function check(authority: IAuthorityType, target: T, Exception: K): T | K | React.ReactNode { + return checkPermissions(authority, CURRENT, target, Exception); +} export default check; diff --git a/src/components/Authorized/PromiseRender.js b/src/components/Authorized/PromiseRender.tsx similarity index 63% rename from src/components/Authorized/PromiseRender.js rename to src/components/Authorized/PromiseRender.tsx index c03a41d483..41db7fa042 100644 --- a/src/components/Authorized/PromiseRender.js +++ b/src/components/Authorized/PromiseRender.tsx @@ -4,16 +4,32 @@ import React from 'react'; // eslint-disable-next-line import/no-cycle import { isComponentClass } from './Secured'; -export default class PromiseRender extends React.Component { - state = { - component: null, +interface IPromiseRenderProps { + ok: T; + error: K; + promise: Promise; +} + +interface IPromiseRenderState { + component: React.ComponentClass | React.FunctionComponent; +} + +export default class PromiseRender extends React.Component< + IPromiseRenderProps, + IPromiseRenderState +> { + state: IPromiseRenderState = { + component: () => null, }; componentDidMount() { this.setRenderComponent(this.props); } - shouldComponentUpdate = (nextProps, nextState) => { + shouldComponentUpdate = ( + nextProps: IPromiseRenderProps, + nextState: IPromiseRenderState, + ) => { const { component } = this.state; if (!isEqual(nextProps, this.props)) { this.setRenderComponent(nextProps); @@ -23,7 +39,7 @@ export default class PromiseRender extends React.Component { }; // set render Component : ok or error - setRenderComponent(props) { + setRenderComponent(props: IPromiseRenderProps) { const ok = this.checkIsInstantiation(props.ok); const error = this.checkIsInstantiation(props.error); props.promise @@ -43,15 +59,17 @@ export default class PromiseRender extends React.Component { // AuthorizedRoute is already instantiated // Authorized render is already instantiated, children is no instantiated // Secured is not instantiated - checkIsInstantiation = target => { + checkIsInstantiation = ( + target: React.ReactNode | React.ComponentClass, + ): React.FunctionComponent => { if (isComponentClass(target)) { - const Target = target; - return props => ; + const Target = target as React.ComponentClass; + return (props: any) => ; } if (React.isValidElement(target)) { - return props => React.cloneElement(target, props); + return (props: any) => React.cloneElement(target, props); } - return () => target; + return () => target as (React.ReactNode & null); }; render() { diff --git a/src/components/Authorized/Secured.js b/src/components/Authorized/Secured.tsx similarity index 71% rename from src/components/Authorized/Secured.js rename to src/components/Authorized/Secured.tsx index bd53b2f55e..4582ed091d 100644 --- a/src/components/Authorized/Secured.js +++ b/src/components/Authorized/Secured.tsx @@ -1,15 +1,15 @@ import React from 'react'; -import Exception from '../Exception'; -// eslint-disable-next-line import/no-cycle import CheckPermissions from './CheckPermissions'; /** * 默认不能访问任何页面 * default is "NULL" */ -const Exception403 = () => ; +const Exception403 = () => 403; -export const isComponentClass = component => { +export const isComponentClass = ( + component: React.ComponentClass | React.ReactNode, +): boolean => { if (!component) return false; const proto = Object.getPrototypeOf(component); if (proto === React.Component || proto === Function.prototype) return true; @@ -20,13 +20,13 @@ export const isComponentClass = component => { // AuthorizedRoute is already instantiated // Authorized render is already instantiated, children is no instantiated // Secured is not instantiated -const checkIsInstantiation = target => { +const checkIsInstantiation = (target: React.ComponentClass | React.ReactNode) => { if (isComponentClass(target)) { - const Target = target; - return props => ; + const Target = target as React.ComponentClass; + return (props: any) => ; } if (React.isValidElement(target)) { - return props => React.cloneElement(target, props); + return (props: any) => React.cloneElement(target, props); } return () => target; }; @@ -46,20 +46,20 @@ const checkIsInstantiation = target => { * @param {string | function | Promise} authority * @param {ReactNode} error 非必需参数 */ -const authorize = (authority, error) => { +const authorize = (authority: string, error?: React.ReactNode) => { /** * conversion into a class * 防止传入字符串时找不到staticContext造成报错 * String parameters can cause staticContext not found error */ - let classError = false; + let classError: boolean | React.FunctionComponent = false; if (error) { - classError = () => error; + classError = (() => error) as React.FunctionComponent; } if (!authority) { throw new Error('authority is required'); } - return function decideAuthority(target) { + return function decideAuthority(target: React.ComponentClass | React.ReactNode) { const component = CheckPermissions(authority, target, classError || Exception403); return checkIsInstantiation(component); }; diff --git a/src/components/Authorized/demo/AuthorizedArray.md b/src/components/Authorized/demo/AuthorizedArray.md deleted file mode 100644 index 1bef5c926b..0000000000 --- a/src/components/Authorized/demo/AuthorizedArray.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -order: 1 -title: - zh-CN: 使用数组作为参数 - en-US: Use Array as a parameter ---- - -Use Array as a parameter - -```jsx -import RenderAuthorized from 'ant-design-pro/lib/Authorized'; -import { Alert } from 'antd'; - -const Authorized = RenderAuthorized('user'); -const noMatch = ; - -ReactDOM.render( - - - , - mountNode -); -``` diff --git a/src/components/Authorized/demo/AuthorizedFunction.md b/src/components/Authorized/demo/AuthorizedFunction.md deleted file mode 100644 index cd3cdd4a72..0000000000 --- a/src/components/Authorized/demo/AuthorizedFunction.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -order: 2 -title: - zh-CN: 使用方法作为参数 - en-US: Use function as a parameter ---- - -Use Function as a parameter - -```jsx -import RenderAuthorized from 'ant-design-pro/lib/Authorized'; -import { Alert } from 'antd'; - -const Authorized = RenderAuthorized('user'); -const noMatch = ; - -const havePermission = () => { - return false; -}; - -ReactDOM.render( - - - , - mountNode -); -``` diff --git a/src/components/Authorized/demo/basic.md b/src/components/Authorized/demo/basic.md deleted file mode 100644 index f40272f436..0000000000 --- a/src/components/Authorized/demo/basic.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -order: 0 -title: - zh-CN: 基本使用 - en-US: Basic use ---- - -Basic use - -```jsx -import RenderAuthorized from 'ant-design-pro/lib/Authorized'; -import { Alert } from 'antd'; - -const Authorized = RenderAuthorized('user'); -const noMatch = ; - -ReactDOM.render( -
- - - -
, - mountNode -); -``` diff --git a/src/components/Authorized/demo/secured.md b/src/components/Authorized/demo/secured.md deleted file mode 100644 index 55d5cd9b30..0000000000 --- a/src/components/Authorized/demo/secured.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -order: 3 -title: - zh-CN: 注解基本使用 - en-US: Basic use secured ---- - -secured demo used - -```jsx -import RenderAuthorized from 'ant-design-pro/lib/Authorized'; -import { Alert } from 'antd'; - -const { Secured } = RenderAuthorized('user'); - -@Secured('admin') -class TestSecuredString extends React.Component { - render() { - return ; - } -} -ReactDOM.render( -
- -
, - mountNode -); -``` diff --git a/src/components/Authorized/index.d.ts b/src/components/Authorized/index.d.ts deleted file mode 100644 index 72c9858797..0000000000 --- a/src/components/Authorized/index.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import AuthorizedRoute, { authority } from './AuthorizedRoute'; -export type IReactComponent

= - | React.StatelessComponent

- | React.ComponentClass

- | React.ClassicComponentClass

; - -type Secured = ( - authority: authority, - error?: React.ReactNode -) => (target: T) => T; - -type check = ( - authority: authority, - target: T, - Exception: S -) => T | S; - -export interface IAuthorizedProps { - authority: authority; - noMatch?: React.ReactNode; -} - -export class Authorized extends React.Component { - public static Secured: Secured; - public static AuthorizedRoute: typeof AuthorizedRoute; - public static check: check; -} - -declare function renderAuthorize(currentAuthority: string): typeof Authorized; - -export default renderAuthorize; diff --git a/src/components/Authorized/index.md b/src/components/Authorized/index.md deleted file mode 100644 index ac09ccaba0..0000000000 --- a/src/components/Authorized/index.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Authorized -subtitle: 权限 -cols: 1 -order: 15 ---- - -权限组件,通过比对现有权限与准入权限,决定相关元素的展示。 - -## API - -### RenderAuthorized - -`RenderAuthorized: (currentAuthority: string | () => string) => Authorized` - -权限组件默认 export RenderAuthorized 函数,它接收当前权限作为参数,返回一个权限对象,该对象提供以下几种使用方式。 - -### Authorized - -最基础的权限控制。 - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| children | 正常渲染的元素,权限判断通过时展示 | ReactNode | - | -| authority | 准入权限/权限判断 | `string | array | Promise | (currentAuthority) => boolean | Promise` | - | -| noMatch | 权限异常渲染元素,权限判断不通过时展示 | ReactNode | - | - -### Authorized.AuthorizedRoute - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| authority | 准入权限/权限判断 | `string | array | Promise | (currentAuthority) => boolean | Promise` | - | -| redirectPath | 权限异常时重定向的页面路由 | string | - | - -其余参数与 `Route` 相同。 - -### Authorized.Secured - -注解方式,`@Authorized.Secured(authority, error)` - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| authority | 准入权限/权限判断 | `string | Promise | (currentAuthority) => boolean | Promise` | - | -| error | 权限异常时渲染元素 | ReactNode | | - -### Authorized.check - -函数形式的 Authorized,用于某些不能被 HOC 包裹的组件。 `Authorized.check(authority, target, Exception)` 注意:传入一个 Promise 时,无论正确还是错误返回的都是一个 ReactClass。 - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| authority | 准入权限/权限判断 | `string | Promise | (currentAuthority) => boolean | Promise` | - | -| target | 权限判断通过时渲染的元素 | ReactNode | - | -| Exception | 权限异常时渲染元素 | ReactNode | - | diff --git a/src/components/Authorized/index.js b/src/components/Authorized/index.tsx similarity index 78% rename from src/components/Authorized/index.js rename to src/components/Authorized/index.tsx index 22ac664d00..9bed79676a 100644 --- a/src/components/Authorized/index.js +++ b/src/components/Authorized/index.tsx @@ -8,4 +8,6 @@ Authorized.Secured = Secured; Authorized.AuthorizedRoute = AuthorizedRoute; Authorized.check = check; -export default renderAuthorize(Authorized); +const RenderAuthorize = renderAuthorize(Authorized); + +export default RenderAuthorize; diff --git a/src/components/Authorized/renderAuthorize.js b/src/components/Authorized/renderAuthorize.ts similarity index 53% rename from src/components/Authorized/renderAuthorize.js rename to src/components/Authorized/renderAuthorize.ts index be373d996b..af7586cc5b 100644 --- a/src/components/Authorized/renderAuthorize.js +++ b/src/components/Authorized/renderAuthorize.ts @@ -1,10 +1,12 @@ -/* eslint-disable import/no-mutable-exports */ -let CURRENT = 'NULL'; +let CURRENT: string | string[] = 'NULL'; +type CurrentAuthorityType = string | string[] | (() => typeof CURRENT); /** * use authority or getAuthority * @param {string|()=>String} currentAuthority */ -const renderAuthorize = Authorized => currentAuthority => { +const renderAuthorize = (Authorized: T): ((currentAuthority: CurrentAuthorityType) => T) => ( + currentAuthority: CurrentAuthorityType, +) => { if (currentAuthority) { if (typeof currentAuthority === 'function') { CURRENT = currentAuthority(); @@ -13,7 +15,7 @@ const renderAuthorize = Authorized => currentAuthority => { Object.prototype.toString.call(currentAuthority) === '[object String]' || Array.isArray(currentAuthority) ) { - CURRENT = currentAuthority; + CURRENT = currentAuthority as string[]; } } else { CURRENT = 'NULL'; @@ -22,4 +24,4 @@ const renderAuthorize = Authorized => currentAuthority => { }; export { CURRENT }; -export default Authorized => renderAuthorize(Authorized); +export default (Authorized: T) => renderAuthorize(Authorized); diff --git a/src/components/AvatarList/AvatarItem.d.ts b/src/components/AvatarList/AvatarItem.d.ts deleted file mode 100644 index 0e809ab458..0000000000 --- a/src/components/AvatarList/AvatarItem.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; - -export declare type SizeType = number | 'small' | 'default' | 'large'; - -export interface AvatarItemProps { - tips: React.ReactNode; - src: string; - size?: SizeType; - style?: React.CSSProperties; - onClick?: () => void; -} - -export default class AvatarItem extends React.Component { - constructor(props: AvatarItemProps); -} diff --git a/src/components/AvatarList/demo/maxLength.md b/src/components/AvatarList/demo/maxLength.md deleted file mode 100644 index 52f0930edd..0000000000 --- a/src/components/AvatarList/demo/maxLength.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -order: 0 -title: - zh-CN: 要显示的最大项目 - en-US: Max Items to Show ---- - -`maxLength` attribute specifies the maximum number of items to show while `excessItemsStyle` style the excess item component. - -```jsx -import AvatarList from 'ant-design-pro/lib/AvatarList'; - -ReactDOM.render( - - - - - - - - , - mountNode -); -``` diff --git a/src/components/AvatarList/demo/simple.md b/src/components/AvatarList/demo/simple.md deleted file mode 100644 index d4438b33ea..0000000000 --- a/src/components/AvatarList/demo/simple.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -order: 0 -title: - zh-CN: 基础样例 - en-US: Basic Usage ---- - -Simplest of usage. - -```jsx -import AvatarList from 'ant-design-pro/lib/AvatarList'; - -ReactDOM.render( - - - - - , - mountNode -); -``` diff --git a/src/components/AvatarList/index.d.ts b/src/components/AvatarList/index.d.ts deleted file mode 100644 index e454a8be4e..0000000000 --- a/src/components/AvatarList/index.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import AvatarItem, { AvatarItemProps, SizeType } from './AvatarItem'; - -export interface AvatarListProps { - Item?: React.ReactElement; - size?: SizeType; - maxLength?: number; - excessItemsStyle?: React.CSSProperties; - style?: React.CSSProperties; - children: React.ReactElement | Array>; -} -export default class AvatarList extends React.Component { - public static Item: typeof AvatarItem; -} diff --git a/src/components/AvatarList/index.en-US.md b/src/components/AvatarList/index.en-US.md deleted file mode 100644 index ee996c31b2..0000000000 --- a/src/components/AvatarList/index.en-US.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: AvatarList -order: 1 -cols: 1 ---- - -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. - -## API - -### AvatarList - -| Property | Description | Type | Default | -| ---------------- | --------------------- | ------------------------------------ | --------- | -| size | size of list | `large`、`small` 、`mini`, `default` | `default` | -| maxLength | max items to show | number | - | -| excessItemsStyle | the excess item style | CSSProperties | - | - -### AvatarList.Item - -| Property | Description | Type | Default | -| -------- | -------------------------------------------- | --------- | ------- | -| tips | title tips for avatar item | ReactNode | - | -| src | the address of the image for an image avatar | string | - | diff --git a/src/components/AvatarList/index.js b/src/components/AvatarList/index.js deleted file mode 100644 index 9af32bcfda..0000000000 --- a/src/components/AvatarList/index.js +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react'; -import { Tooltip, Avatar } from 'antd'; -import classNames from 'classnames'; - -import styles from './index.less'; - -const avatarSizeToClassName = size => - classNames(styles.avatarItem, { - [styles.avatarItemLarge]: size === 'large', - [styles.avatarItemSmall]: size === 'small', - [styles.avatarItemMini]: size === 'mini', - }); - -const AvatarList = ({ children, size, maxLength, excessItemsStyle, ...other }) => { - const numOfChildren = React.Children.count(children); - const numToShow = maxLength >= numOfChildren ? numOfChildren : maxLength; - - const childrenWithProps = React.Children.toArray(children) - .slice(0, numToShow) - .map(child => - React.cloneElement(child, { - size, - }) - ); - - if (numToShow < numOfChildren) { - const cls = avatarSizeToClassName(size); - - childrenWithProps.push( -

  • - {`+${numOfChildren - maxLength}`} -
  • - ); - } - - return ( -
    -
      {childrenWithProps}
    -
    - ); -}; - -const Item = ({ src, size, tips, onClick = () => {} }) => { - const cls = avatarSizeToClassName(size); - - return ( -
  • - {tips ? ( - - - - ) : ( - - )} -
  • - ); -}; - -AvatarList.Item = Item; - -export default AvatarList; diff --git a/src/components/AvatarList/index.less b/src/components/AvatarList/index.less deleted file mode 100644 index 45904ce6ae..0000000000 --- a/src/components/AvatarList/index.less +++ /dev/null @@ -1,50 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.avatarList { - display: inline-block; - ul { - display: inline-block; - margin-left: 8px; - font-size: 0; - } -} - -.avatarItem { - display: inline-block; - width: @avatar-size-base; - height: @avatar-size-base; - margin-left: -8px; - font-size: @font-size-base; - :global { - .ant-avatar { - border: 1px solid #fff; - } - } -} - -.avatarItemLarge { - width: @avatar-size-lg; - height: @avatar-size-lg; -} - -.avatarItemSmall { - width: @avatar-size-sm; - height: @avatar-size-sm; -} - -.avatarItemMini { - width: 20px; - height: 20px; - :global { - .ant-avatar { - width: 20px; - height: 20px; - line-height: 20px; - - .ant-avatar-string { - font-size: 12px; - line-height: 18px; - } - } - } -} diff --git a/src/components/AvatarList/index.test.js b/src/components/AvatarList/index.test.js deleted file mode 100644 index 2b5bc438d8..0000000000 --- a/src/components/AvatarList/index.test.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import range from 'lodash/range'; -import { mount } from 'enzyme'; -import AvatarList from './index'; - -const renderItems = numItems => - range(numItems).map(i => ( - - )); - -describe('AvatarList', () => { - it('renders all items', () => { - const wrapper = mount({renderItems(4)}); - expect(wrapper.find('AvatarList').length).toBe(1); - expect(wrapper.find('Item').length).toBe(4); - expect(wrapper.findWhere(node => node.key() === 'exceed').length).toBe(0); - }); - - it('renders max of 3 items', () => { - const wrapper = mount({renderItems(4)}); - expect(wrapper.find('AvatarList').length).toBe(1); - expect(wrapper.find('Item').length).toBe(3); - expect(wrapper.findWhere(node => node.key() === 'exceed').length).toBe(1); - }); -}); diff --git a/src/components/AvatarList/index.zh-CN.md b/src/components/AvatarList/index.zh-CN.md deleted file mode 100644 index 5c04acaf89..0000000000 --- a/src/components/AvatarList/index.zh-CN.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: AvatarList -subtitle: 用户头像列表 -order: 1 -cols: 1 ---- - -一组用户头像,常用在项目/团队成员列表。可通过设置 `size` 属性来指定头像大小。 - -## API - -### AvatarList - -| 参数 | 说明 | 类型 | 默认值 | -| ---------------- | ---------------- | ------------------------------------ | --------- | -| size | 头像大小 | `large`、`small` 、`mini`, `default` | `default` | -| maxLength | 要显示的最大项目 | number | - | -| excessItemsStyle | 多余的项目风格 | CSSProperties | - | - -### AvatarList.Item - -| 参数 | 说明 | 类型 | 默认值 | -| ---- | ------------ | --------- | ------ | -| tips | 头像展示文案 | ReactNode | - | -| src | 头像图片连接 | string | - | diff --git a/src/components/Charts/Bar/index.d.ts b/src/components/Charts/Bar/index.d.ts deleted file mode 100644 index 67bb1dd0cd..0000000000 --- a/src/components/Charts/Bar/index.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -export interface IBarProps { - title: React.ReactNode; - color?: string; - padding?: [number, number, number, number]; - height: number; - data: Array<{ - x: string; - y: number; - }>; - autoLabel?: boolean; - style?: React.CSSProperties; -} - -export default class Bar extends React.Component {} diff --git a/src/components/Charts/Bar/index.js b/src/components/Charts/Bar/index.js deleted file mode 100644 index 2f7ee243b0..0000000000 --- a/src/components/Charts/Bar/index.js +++ /dev/null @@ -1,124 +0,0 @@ -import React, { Component } from 'react'; -import { Chart, Axis, Tooltip, Geom } from 'bizcharts'; -import Debounce from 'lodash-decorators/debounce'; -import Bind from 'lodash-decorators/bind'; -import ResizeObserver from 'resize-observer-polyfill'; -import styles from '../index.less'; - -class Bar extends Component { - state = { - height: 0, - autoHideXLabels: false, - }; - - handleRoot = n => { - this.root = n; - }; - - handleRef = n => { - this.node = n; - }; - - resizeObserver() { - const ro = new ResizeObserver(entries => { - const { width, height } = entries[0].contentRect; - this.resize(); - this.setState(preState => { - if (preState.width !== width || preState.height !== height) { - return { - height, - }; - } - return null; - }); - }); - if (this.root) { - ro.observe(this.root); - } - } - - @Bind() - @Debounce(400) - resize() { - if (!this.node) { - return; - } - const canvasWidth = this.node.parentNode.clientWidth; - const { data = [], autoLabel = true } = this.props; - if (!autoLabel) { - return; - } - const minWidth = data.length * 30; - const { autoHideXLabels } = this.state; - - if (canvasWidth <= minWidth) { - if (!autoHideXLabels) { - this.setState({ - autoHideXLabels: true, - }); - } - } else if (autoHideXLabels) { - this.setState({ - autoHideXLabels: false, - }); - } - } - - render() { - const { - height: propsHeight, - title, - forceFit = true, - data, - color = 'rgba(24, 144, 255, 0.85)', - padding, - } = this.props; - - const { autoHideXLabels } = this.state; - - const scale = { - x: { - type: 'cat', - }, - y: { - min: 0, - }, - }; - - const tooltip = [ - 'x*y', - (x, y) => ({ - name: x, - value: y, - }), - ]; - const { height: stateHeight } = this.state; - const height = propsHeight || stateHeight; - return ( -
    -
    - {title &&

    {title}

    } - - - - - - -
    -
    - ); - } -} - -export default Bar; diff --git a/src/components/Charts/ChartCard/index.d.ts b/src/components/Charts/ChartCard/index.d.ts deleted file mode 100644 index 5153f5e062..0000000000 --- a/src/components/Charts/ChartCard/index.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { CardProps } from 'antd/lib/card'; -import React from 'react'; - -export interface IChartCardProps extends CardProps { - title: React.ReactNode; - action?: React.ReactNode; - total?: React.ReactNode | number | (() => React.ReactNode | number); - footer?: React.ReactNode; - contentHeight?: number; - avatar?: React.ReactNode; - style?: React.CSSProperties; -} - -export default class ChartCard extends React.Component {} diff --git a/src/components/Charts/ChartCard/index.js b/src/components/Charts/ChartCard/index.js deleted file mode 100644 index ca6bcb2e6d..0000000000 --- a/src/components/Charts/ChartCard/index.js +++ /dev/null @@ -1,82 +0,0 @@ -import React from 'react'; -import { Card } from 'antd'; -import classNames from 'classnames'; - -import styles from './index.less'; - -const renderTotal = total => { - let totalDom; - switch (typeof total) { - case 'undefined': - totalDom = null; - break; - case 'function': - totalDom =
    {total()}
    ; - break; - default: - totalDom =
    {total}
    ; - } - return totalDom; -}; - -class ChartCard extends React.PureComponent { - renderConnet = () => { - const { contentHeight, title, avatar, action, total, footer, children, loading } = this.props; - if (loading) { - return false; - } - return ( -
    -
    -
    {avatar}
    -
    -
    - {title} - {action} -
    - {renderTotal(total)} -
    -
    - {children && ( -
    -
    {children}
    -
    - )} - {footer && ( -
    - {footer} -
    - )} -
    - ); - }; - - render() { - const { - loading = false, - contentHeight, - title, - avatar, - action, - total, - footer, - children, - ...rest - } = this.props; - return ( - - {this.renderConnet()} - - ); - } -} - -export default ChartCard; diff --git a/src/components/Charts/ChartCard/index.less b/src/components/Charts/ChartCard/index.less deleted file mode 100644 index 282f17d9cf..0000000000 --- a/src/components/Charts/ChartCard/index.less +++ /dev/null @@ -1,75 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.chartCard { - position: relative; - .chartTop { - position: relative; - width: 100%; - overflow: hidden; - } - .chartTopMargin { - margin-bottom: 12px; - } - .chartTopHasMargin { - margin-bottom: 20px; - } - .metaWrap { - float: left; - } - .avatar { - position: relative; - top: 4px; - float: left; - margin-right: 20px; - img { - border-radius: 100%; - } - } - .meta { - height: 22px; - color: @text-color-secondary; - font-size: @font-size-base; - line-height: 22px; - } - .action { - position: absolute; - top: 4px; - right: 0; - line-height: 1; - cursor: pointer; - } - .total { - height: 38px; - margin-top: 4px; - margin-bottom: 0; - overflow: hidden; - color: @heading-color; - font-size: 30px; - line-height: 38px; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - } - .content { - position: relative; - width: 100%; - margin-bottom: 12px; - } - .contentFixed { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - } - .footer { - margin-top: 8px; - padding-top: 9px; - border-top: 1px solid @border-color-split; - & > * { - position: relative; - } - } - .footerMargin { - margin-top: 20px; - } -} diff --git a/src/components/Charts/Field/index.d.ts b/src/components/Charts/Field/index.d.ts deleted file mode 100644 index 80b1bf1d71..0000000000 --- a/src/components/Charts/Field/index.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -export interface IFieldProps { - label: React.ReactNode; - value: React.ReactNode; - style?: React.CSSProperties; -} - -export default class Field extends React.Component {} diff --git a/src/components/Charts/Field/index.js b/src/components/Charts/Field/index.js deleted file mode 100644 index 22dca86c0d..0000000000 --- a/src/components/Charts/Field/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - -import styles from './index.less'; - -const Field = ({ label, value, ...rest }) => ( -
    - {label} - {value} -
    -); - -export default Field; diff --git a/src/components/Charts/Field/index.less b/src/components/Charts/Field/index.less deleted file mode 100644 index 4124471cb5..0000000000 --- a/src/components/Charts/Field/index.less +++ /dev/null @@ -1,17 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.field { - margin: 0; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - .label, - .number { - font-size: @font-size-base; - line-height: 22px; - } - .number { - margin-left: 8px; - color: @heading-color; - } -} diff --git a/src/components/Charts/Gauge/index.d.ts b/src/components/Charts/Gauge/index.d.ts deleted file mode 100644 index fe5500918c..0000000000 --- a/src/components/Charts/Gauge/index.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -export interface IGaugeProps { - title: React.ReactNode; - color?: string; - height: number; - bgColor?: number; - percent: number; - style?: React.CSSProperties; -} - -export default class Gauge extends React.Component {} diff --git a/src/components/Charts/Gauge/index.js b/src/components/Charts/Gauge/index.js deleted file mode 100644 index e97f126e6e..0000000000 --- a/src/components/Charts/Gauge/index.js +++ /dev/null @@ -1,167 +0,0 @@ -import React from 'react'; -import { Chart, Geom, Axis, Coord, Guide, Shape } from 'bizcharts'; -import autoHeight from '../autoHeight'; - -const { Arc, Html, Line } = Guide; - -const defaultFormatter = val => { - switch (val) { - case '2': - return '差'; - case '4': - return '中'; - case '6': - return '良'; - case '8': - return '优'; - default: - return ''; - } -}; - -Shape.registerShape('point', 'pointer', { - drawShape(cfg, group) { - let point = cfg.points[0]; - point = this.parsePoint(point); - const center = this.parsePoint({ - x: 0, - y: 0, - }); - group.addShape('line', { - attrs: { - x1: center.x, - y1: center.y, - x2: point.x, - y2: point.y, - stroke: cfg.color, - lineWidth: 2, - lineCap: 'round', - }, - }); - return group.addShape('circle', { - attrs: { - x: center.x, - y: center.y, - r: 6, - stroke: cfg.color, - lineWidth: 3, - fill: '#fff', - }, - }); - }, -}); - -@autoHeight() -class Gauge extends React.Component { - render() { - const { - title, - height, - percent, - forceFit = true, - formatter = defaultFormatter, - color = '#2F9CFF', - bgColor = '#F0F2F5', - } = this.props; - const cols = { - value: { - type: 'linear', - min: 0, - max: 10, - tickCount: 6, - nice: true, - }, - }; - const data = [{ value: percent / 10 }]; - return ( - - - - - - - - - - - ` -
    -

    ${title}

    -

    - ${(data[0].value * 10).toFixed(2)}% -

    -
    `} - /> -
    - -
    - ); - } -} - -export default Gauge; diff --git a/src/components/Charts/MiniArea/index.d.ts b/src/components/Charts/MiniArea/index.d.ts deleted file mode 100644 index 8b4e71cab7..0000000000 --- a/src/components/Charts/MiniArea/index.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; - -// g2已经更新到3.0 -// 不带的写了 - -export interface IAxis { - title: any; - line: any; - gridAlign: any; - labels: any; - tickLine: any; - grid: any; -} - -export interface IMiniAreaProps { - color?: string; - height: number; - borderColor?: string; - line?: boolean; - animate?: boolean; - xAxis?: IAxis; - yAxis?: IAxis; - data: Array<{ - x: number | string; - y: number; - }>; -} - -export default class MiniArea extends React.Component {} diff --git a/src/components/Charts/MiniArea/index.js b/src/components/Charts/MiniArea/index.js deleted file mode 100644 index d3209becae..0000000000 --- a/src/components/Charts/MiniArea/index.js +++ /dev/null @@ -1,108 +0,0 @@ -import React from 'react'; -import { Chart, Axis, Tooltip, Geom } from 'bizcharts'; -import autoHeight from '../autoHeight'; -import styles from '../index.less'; - -@autoHeight() -class MiniArea extends React.PureComponent { - render() { - const { - height, - data = [], - forceFit = true, - color = 'rgba(24, 144, 255, 0.2)', - borderColor = '#1089ff', - scale = {}, - borderWidth = 2, - line, - xAxis, - yAxis, - animate = true, - } = this.props; - - const padding = [36, 5, 30, 5]; - - const scaleProps = { - x: { - type: 'cat', - range: [0, 1], - ...scale.x, - }, - y: { - min: 0, - ...scale.y, - }, - }; - - const tooltip = [ - 'x*y', - (x, y) => ({ - name: x, - value: y, - }), - ]; - - const chartHeight = height + 54; - - return ( -
    -
    - {height > 0 && ( - - - - - - {line ? ( - - ) : ( - - )} - - )} -
    -
    - ); - } -} - -export default MiniArea; diff --git a/src/components/Charts/MiniBar/index.d.ts b/src/components/Charts/MiniBar/index.d.ts deleted file mode 100644 index b2685339ea..0000000000 --- a/src/components/Charts/MiniBar/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -export interface IMiniBarProps { - color?: string; - height: number; - data: Array<{ - x: number | string; - y: number; - }>; - style?: React.CSSProperties; -} - -export default class MiniBar extends React.Component {} diff --git a/src/components/Charts/MiniBar/index.js b/src/components/Charts/MiniBar/index.js deleted file mode 100644 index 18e4d8c6fb..0000000000 --- a/src/components/Charts/MiniBar/index.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import { Chart, Tooltip, Geom } from 'bizcharts'; -import autoHeight from '../autoHeight'; -import styles from '../index.less'; - -@autoHeight() -class MiniBar extends React.Component { - render() { - const { height, forceFit = true, color = '#1890FF', data = [] } = this.props; - - const scale = { - x: { - type: 'cat', - }, - y: { - min: 0, - }, - }; - - const padding = [36, 5, 30, 5]; - - const tooltip = [ - 'x*y', - (x, y) => ({ - name: x, - value: y, - }), - ]; - - // for tooltip not to be hide - const chartHeight = height + 54; - - return ( -
    -
    - - - - -
    -
    - ); - } -} -export default MiniBar; diff --git a/src/components/Charts/MiniProgress/index.d.ts b/src/components/Charts/MiniProgress/index.d.ts deleted file mode 100644 index 6111d88d58..0000000000 --- a/src/components/Charts/MiniProgress/index.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -export interface IMiniProgressProps { - target: number; - targetLabel: string; - color?: string; - strokeWidth?: number; - percent?: number; - style?: React.CSSProperties; -} - -export default class MiniProgress extends React.Component {} diff --git a/src/components/Charts/MiniProgress/index.js b/src/components/Charts/MiniProgress/index.js deleted file mode 100644 index dd5712e8a8..0000000000 --- a/src/components/Charts/MiniProgress/index.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import { Tooltip } from 'antd'; -import styles from './index.less'; - -const MiniProgress = ({ - targetLabel, - target, - color = 'rgb(19, 194, 194)', - strokeWidth, - percent, -}) => { - return ( -
    - -
    - - -
    -
    -
    -
    -
    -
    - ); -}; - -export default MiniProgress; diff --git a/src/components/Charts/MiniProgress/index.less b/src/components/Charts/MiniProgress/index.less deleted file mode 100644 index e1e0b4fc51..0000000000 --- a/src/components/Charts/MiniProgress/index.less +++ /dev/null @@ -1,37 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.miniProgress { - position: relative; - width: 100%; - padding: 5px 0; - .progressWrap { - position: relative; - background-color: @background-color-base; - } - .progress { - width: 0; - height: 100%; - background-color: @primary-color; - border-radius: 1px 0 0 1px; - transition: all 0.4s cubic-bezier(0.08, 0.82, 0.17, 1) 0s; - } - .target { - position: absolute; - top: 0; - bottom: 0; - z-index: 9; - width: 20px; - span { - position: absolute; - top: 0; - left: 0; - width: 2px; - height: 4px; - border-radius: 100px; - } - span:last-child { - top: auto; - bottom: 0; - } - } -} diff --git a/src/components/Charts/Pie/index.d.ts b/src/components/Charts/Pie/index.d.ts deleted file mode 100644 index 63aecfa3d6..0000000000 --- a/src/components/Charts/Pie/index.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -export interface IPieProps { - animate?: boolean; - color?: string; - colors?: string[]; - height: number; - hasLegend?: boolean; - padding?: [number, number, number, number]; - percent?: number; - data?: Array<{ - x: string | string; - y: number; - }>; - total?: React.ReactNode | number | (() => React.ReactNode | number); - title?: React.ReactNode; - tooltip?: boolean; - valueFormat?: (value: string) => string | React.ReactNode; - subTitle?: React.ReactNode; -} - -export default class Pie extends React.Component {} diff --git a/src/components/Charts/Pie/index.js b/src/components/Charts/Pie/index.js deleted file mode 100644 index ae3201f22d..0000000000 --- a/src/components/Charts/Pie/index.js +++ /dev/null @@ -1,248 +0,0 @@ -import React, { Component } from 'react'; -import { Chart, Tooltip, Geom, Coord } from 'bizcharts'; -import { DataView } from '@antv/data-set'; -import { Divider } from 'antd'; -import classNames from 'classnames'; -import ReactFitText from 'react-fittext'; -import Debounce from 'lodash-decorators/debounce'; -import Bind from 'lodash-decorators/bind'; -import styles from './index.less'; - -/* eslint react/no-danger:0 */ -class Pie extends Component { - state = { - height: 0, - legendData: [], - legendBlock: false, - }; - - componentDidUpdate(preProps) { - const { data } = this.props; - if (data !== preProps.data) { - // because of charts data create when rendered - // so there is a trick for get rendered time - this.getLegendData(); - } - } - - getG2Instance = chart => { - this.chart = chart; - requestAnimationFrame(() => { - this.getLegendData(); - }); - }; - - // for custom lengend view - getLegendData = () => { - if (!this.chart) return; - const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形 - if (!geom) return; - const items = geom.get('dataArray') || []; // 获取图形对应的 - - const legendData = items.map(item => { - /* eslint no-underscore-dangle:0 */ - const origin = item[0]._origin; - origin.color = item[0].color; - origin.checked = true; - return origin; - }); - - this.setState({ - legendData, - }); - }; - - handleRoot = n => { - this.root = n; - }; - - handleLegendClick = (item, i) => { - const newItem = item; - newItem.checked = !newItem.checked; - - const { legendData } = this.state; - legendData[i] = newItem; - - const filteredLegendData = legendData.filter(l => l.checked).map(l => l.x); - - if (this.chart) { - this.chart.filter('x', val => filteredLegendData.indexOf(val) > -1); - } - - this.setState({ - legendData, - }); - }; - - // for window resize auto responsive legend - @Bind() - @Debounce(300) - resize() { - const { hasLegend } = this.props; - const { legendBlock } = this.state; - if (!hasLegend || !this.root) { - window.removeEventListener('resize', this.resize); - return; - } - if (this.root.parentNode.clientWidth <= 380) { - if (!legendBlock) { - this.setState({ - legendBlock: true, - }); - } - } else if (legendBlock) { - this.setState({ - legendBlock: false, - }); - } - } - - render() { - const { - valueFormat, - subTitle, - total, - hasLegend = false, - className, - style, - height, - percent, - color, - inner = 0.75, - animate = true, - colors, - lineWidth = 1, - } = this.props; - - const { legendData, height: stateHeight, legendBlock } = this.state; - const pieClassName = classNames(styles.pie, className, { - [styles.hasLegend]: !!hasLegend, - [styles.legendBlock]: legendBlock, - }); - - const { - data: propsData, - selected: propsSelected = true, - tooltip: propsTooltip = true, - } = this.props; - - let data = propsData || []; - let selected = propsSelected; - let tooltip = propsTooltip; - - const defaultColors = colors; - selected = selected || true; - tooltip = tooltip || true; - let formatColor; - - const scale = { - x: { - type: 'cat', - range: [0, 1], - }, - y: { - min: 0, - }, - }; - - if (percent || percent === 0) { - selected = false; - tooltip = false; - formatColor = value => { - if (value === '占比') { - return color || 'rgba(24, 144, 255, 0.85)'; - } - return '#F0F2F5'; - }; - - data = [ - { - x: '占比', - y: parseFloat(percent), - }, - { - x: '反比', - y: 100 - parseFloat(percent), - }, - ]; - } - - const tooltipFormat = [ - 'x*percent', - (x, p) => ({ - name: x, - value: `${(p * 100).toFixed(2)}%`, - }), - ]; - - const padding = [12, 0, 12, 0]; - - const dv = new DataView(); - dv.source(data).transform({ - type: 'percent', - field: 'y', - dimension: 'x', - as: 'percent', - }); - - return ( -
    - -
    - - {!!tooltip && } - - - - - {(subTitle || total) && ( -
    - {subTitle &&

    {subTitle}

    } - {/* eslint-disable-next-line */} - {total && ( -
    {typeof total === 'function' ? total() : total}
    - )} -
    - )} -
    -
    - {hasLegend && ( -
      - {legendData.map((item, i) => ( -
    • this.handleLegendClick(item, i)}> - - {item.x} - - - {`${(Number.isNaN(item.percent) ? 0 : item.percent * 100).toFixed(2)}%`} - - {valueFormat ? valueFormat(item.y) : item.y} -
    • - ))} -
    - )} -
    - ); - } -} - -export default Pie; diff --git a/src/components/Charts/Pie/index.less b/src/components/Charts/Pie/index.less deleted file mode 100644 index fc961b41df..0000000000 --- a/src/components/Charts/Pie/index.less +++ /dev/null @@ -1,94 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.pie { - position: relative; - .chart { - position: relative; - } - &.hasLegend .chart { - width: ~'calc(100% - 240px)'; - } - .legend { - position: absolute; - top: 50%; - right: 0; - min-width: 200px; - margin: 0 20px; - padding: 0; - list-style: none; - transform: translateY(-50%); - li { - height: 22px; - margin-bottom: 16px; - line-height: 22px; - cursor: pointer; - &:last-child { - margin-bottom: 0; - } - } - } - .dot { - position: relative; - top: -1px; - display: inline-block; - width: 8px; - height: 8px; - margin-right: 8px; - border-radius: 8px; - } - .line { - display: inline-block; - width: 1px; - height: 16px; - margin-right: 8px; - background-color: @border-color-split; - } - .legendTitle { - color: @text-color; - } - .percent { - color: @text-color-secondary; - } - .value { - position: absolute; - right: 0; - } - .title { - margin-bottom: 8px; - } - .total { - position: absolute; - top: 50%; - left: 50%; - max-height: 62px; - text-align: center; - transform: translate(-50%, -50%); - & > h4 { - height: 22px; - margin-bottom: 8px; - color: @text-color-secondary; - font-weight: normal; - font-size: 14px; - line-height: 22px; - } - & > p { - display: block; - height: 32px; - color: @heading-color; - font-size: 1.2em; - line-height: 32px; - white-space: nowrap; - } - } -} - -.legendBlock { - &.hasLegend .chart { - width: 100%; - margin: 0 0 32px 0; - } - .legend { - position: relative; - transform: none; - } -} diff --git a/src/components/Charts/Radar/index.d.ts b/src/components/Charts/Radar/index.d.ts deleted file mode 100644 index 6a7dd42afe..0000000000 --- a/src/components/Charts/Radar/index.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -export interface IRadarProps { - title?: React.ReactNode; - height: number; - padding?: [number, number, number, number]; - hasLegend?: boolean; - data: Array<{ - name: string; - label: string; - value: string; - }>; - style?: React.CSSProperties; -} - -export default class Radar extends React.Component {} diff --git a/src/components/Charts/Radar/index.js b/src/components/Charts/Radar/index.js deleted file mode 100644 index a0aa7fab6e..0000000000 --- a/src/components/Charts/Radar/index.js +++ /dev/null @@ -1,184 +0,0 @@ -import React, { Component } from 'react'; -import { Chart, Tooltip, Geom, Coord, Axis } from 'bizcharts'; -import { Row, Col } from 'antd'; -import autoHeight from '../autoHeight'; -import styles from './index.less'; - -/* eslint react/no-danger:0 */ -@autoHeight() -class Radar extends Component { - state = { - legendData: [], - }; - - componentDidMount() { - this.getLegendData(); - } - - componentDidUpdate(preProps) { - const { data } = this.props; - if (data !== preProps.data) { - this.getLegendData(); - } - } - - getG2Instance = chart => { - this.chart = chart; - }; - - // for custom lengend view - getLegendData = () => { - if (!this.chart) return; - const geom = this.chart.getAllGeoms()[0]; // 获取所有的图形 - if (!geom) return; - const items = geom.get('dataArray') || []; // 获取图形对应的 - - const legendData = items.map(item => { - // eslint-disable-next-line - const origins = item.map(t => t._origin); - const result = { - name: origins[0].name, - color: item[0].color, - checked: true, - value: origins.reduce((p, n) => p + n.value, 0), - }; - - return result; - }); - - this.setState({ - legendData, - }); - }; - - handleRef = n => { - this.node = n; - }; - - handleLegendClick = (item, i) => { - const newItem = item; - newItem.checked = !newItem.checked; - - const { legendData } = this.state; - legendData[i] = newItem; - - const filteredLegendData = legendData.filter(l => l.checked).map(l => l.name); - - if (this.chart) { - this.chart.filter('name', val => filteredLegendData.indexOf(val) > -1); - this.chart.repaint(); - } - - this.setState({ - legendData, - }); - }; - - render() { - const defaultColors = [ - '#1890FF', - '#FACC14', - '#2FC25B', - '#8543E0', - '#F04864', - '#13C2C2', - '#fa8c16', - '#a0d911', - ]; - - const { - data = [], - height = 0, - title, - hasLegend = false, - forceFit = true, - tickCount = 5, - padding = [35, 30, 16, 30], - animate = true, - colors = defaultColors, - } = this.props; - - const { legendData } = this.state; - - const scale = { - value: { - min: 0, - tickCount, - }, - }; - - const chartHeight = height - (hasLegend ? 80 : 22); - - return ( -
    - {title &&

    {title}

    } - - - - - - - - - {hasLegend && ( - - {legendData.map((item, i) => ( - this.handleLegendClick(item, i)} - > -
    -

    - - {item.name} -

    -
    {item.value}
    -
    - - ))} -
    - )} -
    - ); - } -} - -export default Radar; diff --git a/src/components/Charts/Radar/index.less b/src/components/Charts/Radar/index.less deleted file mode 100644 index 437a71297e..0000000000 --- a/src/components/Charts/Radar/index.less +++ /dev/null @@ -1,46 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.radar { - .legend { - margin-top: 16px; - .legendItem { - position: relative; - color: @text-color-secondary; - line-height: 22px; - text-align: center; - cursor: pointer; - p { - margin: 0; - } - h6 { - margin-top: 4px; - margin-bottom: 0; - padding-left: 16px; - color: @heading-color; - font-size: 24px; - line-height: 32px; - } - &::after { - position: absolute; - top: 8px; - right: 0; - width: 1px; - height: 40px; - background-color: @border-color-split; - content: ''; - } - } - > :last-child .legendItem::after { - display: none; - } - .dot { - position: relative; - top: -1px; - display: inline-block; - width: 6px; - height: 6px; - margin-right: 6px; - border-radius: 6px; - } - } -} diff --git a/src/components/Charts/TagCloud/index.d.ts b/src/components/Charts/TagCloud/index.d.ts deleted file mode 100644 index ac25269dfe..0000000000 --- a/src/components/Charts/TagCloud/index.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -export interface ITagCloudProps { - data: Array<{ - name: string; - value: number; - }>; - height: number; - style?: React.CSSProperties; -} - -export default class TagCloud extends React.Component {} diff --git a/src/components/Charts/TagCloud/index.js b/src/components/Charts/TagCloud/index.js deleted file mode 100644 index 2f60124aae..0000000000 --- a/src/components/Charts/TagCloud/index.js +++ /dev/null @@ -1,167 +0,0 @@ -import React, { Component } from 'react'; -import { Chart, Geom, Coord, Shape, Tooltip } from 'bizcharts'; -import DataSet from '@antv/data-set'; -import Debounce from 'lodash-decorators/debounce'; -import Bind from 'lodash-decorators/bind'; -import classNames from 'classnames'; -import autoHeight from '../autoHeight'; -import styles from './index.less'; - -/* eslint no-underscore-dangle: 0 */ -/* eslint no-param-reassign: 0 */ - -const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png'; - -@autoHeight() -class TagCloud extends Component { - state = { - dv: null, - }; - - componentDidMount() { - this.initTagCloud(); - this.renderChart(); - } - - componentDidUpdate(preProps) { - const { data } = this.props; - if (JSON.stringify(preProps.data) !== JSON.stringify(data)) { - this.renderChart(this.props); - } - } - - componentWillUnmount() { - this.isUnmount = true; - } - - saveRootRef = node => { - this.root = node; - }; - - initTagCloud = () => { - function getTextAttrs(cfg) { - return Object.assign({}, cfg.style, { - fillOpacity: cfg.opacity, - fontSize: cfg.origin._origin.size, - rotate: cfg.origin._origin.rotate, - text: cfg.origin._origin.text, - textAlign: 'center', - fontFamily: cfg.origin._origin.font, - fill: cfg.color, - textBaseline: 'Alphabetic', - }); - } - - // 给point注册一个词云的shape - Shape.registerShape('point', 'cloud', { - drawShape(cfg, container) { - const attrs = getTextAttrs(cfg); - return container.addShape('text', { - attrs: Object.assign(attrs, { - x: cfg.x, - y: cfg.y, - }), - }); - }, - }); - }; - - @Bind() - @Debounce(500) - renderChart(nextProps) { - // const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C']; - const { data, height } = nextProps || this.props; - - if (data.length < 1 || !this.root) { - return; - } - - const h = height; - const w = this.root.offsetWidth; - - const onload = () => { - const dv = new DataSet.View().source(data); - const range = dv.range('value'); - const [min, max] = range; - dv.transform({ - type: 'tag-cloud', - fields: ['name', 'value'], - imageMask: this.imageMask, - font: 'Verdana', - size: [w, h], // 宽高设置最好根据 imageMask 做调整 - padding: 0, - timeInterval: 5000, // max execute time - rotate() { - return 0; - }, - fontSize(d) { - // eslint-disable-next-line - return Math.pow((d.value - min) / (max - min), 2) * (17.5 - 5) + 5; - }, - }); - - if (this.isUnmount) { - return; - } - - this.setState({ - dv, - w, - h, - }); - }; - - if (!this.imageMask) { - this.imageMask = new Image(); - this.imageMask.crossOrigin = ''; - this.imageMask.src = imgUrl; - - this.imageMask.onload = onload; - } else { - onload(); - } - } - - render() { - const { className, height } = this.props; - const { dv, w, h } = this.state; - - return ( -
    - {dv && ( - - - - - - )} -
    - ); - } -} - -export default TagCloud; diff --git a/src/components/Charts/TagCloud/index.less b/src/components/Charts/TagCloud/index.less deleted file mode 100644 index db8e4dabfd..0000000000 --- a/src/components/Charts/TagCloud/index.less +++ /dev/null @@ -1,6 +0,0 @@ -.tagCloud { - overflow: hidden; - canvas { - transform-origin: 0 0; - } -} diff --git a/src/components/Charts/TimelineChart/index.d.ts b/src/components/Charts/TimelineChart/index.d.ts deleted file mode 100644 index 0f547e7736..0000000000 --- a/src/components/Charts/TimelineChart/index.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -export interface ITimelineChartProps { - data: Array<{ - x: number; - y1: number; - y2?: number; - }>; - titleMap: { y1: string; y2?: string }; - padding?: [number, number, number, number]; - height?: number; - style?: React.CSSProperties; -} - -export default class TimelineChart extends React.Component {} diff --git a/src/components/Charts/TimelineChart/index.js b/src/components/Charts/TimelineChart/index.js deleted file mode 100644 index d82623c580..0000000000 --- a/src/components/Charts/TimelineChart/index.js +++ /dev/null @@ -1,120 +0,0 @@ -import React from 'react'; -import { Chart, Tooltip, Geom, Legend, Axis } from 'bizcharts'; -import DataSet from '@antv/data-set'; -import Slider from 'bizcharts-plugin-slider'; -import autoHeight from '../autoHeight'; -import styles from './index.less'; - -@autoHeight() -class TimelineChart extends React.Component { - render() { - const { - title, - height = 400, - padding = [60, 20, 40, 40], - titleMap = { - y1: 'y1', - y2: 'y2', - }, - borderWidth = 2, - data: sourceData, - } = this.props; - - const data = Array.isArray(sourceData) ? sourceData : [{ x: 0, y1: 0, y2: 0 }]; - - data.sort((a, b) => a.x - b.x); - - let max; - if (data[0] && data[0].y1 && data[0].y2) { - max = Math.max( - [...data].sort((a, b) => b.y1 - a.y1)[0].y1, - [...data].sort((a, b) => b.y2 - a.y2)[0].y2 - ); - } - - const ds = new DataSet({ - state: { - start: data[0].x, - end: data[data.length - 1].x, - }, - }); - - const dv = ds.createView(); - dv.source(data) - .transform({ - type: 'filter', - callback: obj => { - const date = obj.x; - return date <= ds.state.end && date >= ds.state.start; - }, - }) - .transform({ - type: 'map', - callback(row) { - const newRow = { ...row }; - newRow[titleMap.y1] = row.y1; - newRow[titleMap.y2] = row.y2; - return newRow; - }, - }) - .transform({ - type: 'fold', - fields: [titleMap.y1, titleMap.y2], // 展开字段集 - key: 'key', // key字段 - value: 'value', // value字段 - }); - - const timeScale = { - type: 'time', - tickInterval: 60 * 60 * 1000, - mask: 'HH:mm', - range: [0, 1], - }; - - const cols = { - x: timeScale, - value: { - max, - min: 0, - }, - }; - - const SliderGen = () => ( - { - ds.setState('start', startValue); - ds.setState('end', endValue); - }} - /> - ); - - return ( -
    -
    - {title &&

    {title}

    } - - - - - - -
    - -
    -
    -
    - ); - } -} - -export default TimelineChart; diff --git a/src/components/Charts/TimelineChart/index.less b/src/components/Charts/TimelineChart/index.less deleted file mode 100644 index 1751975692..0000000000 --- a/src/components/Charts/TimelineChart/index.less +++ /dev/null @@ -1,3 +0,0 @@ -.timelineChart { - background: #fff; -} diff --git a/src/components/Charts/WaterWave/index.d.ts b/src/components/Charts/WaterWave/index.d.ts deleted file mode 100644 index e30a7e48f7..0000000000 --- a/src/components/Charts/WaterWave/index.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -export interface IWaterWaveProps { - title: React.ReactNode; - color?: string; - height: number; - percent: number; - style?: React.CSSProperties; -} - -export default class WaterWave extends React.Component {} diff --git a/src/components/Charts/WaterWave/index.js b/src/components/Charts/WaterWave/index.js deleted file mode 100644 index 055f7c7346..0000000000 --- a/src/components/Charts/WaterWave/index.js +++ /dev/null @@ -1,213 +0,0 @@ -import React, { PureComponent } from 'react'; -import autoHeight from '../autoHeight'; -import styles from './index.less'; - -/* eslint no-return-assign: 0 */ -/* eslint no-mixed-operators: 0 */ -// riddle: https://riddle.alibaba-inc.com/riddles/2d9a4b90 - -@autoHeight() -class WaterWave extends PureComponent { - state = { - radio: 1, - }; - - componentDidMount() { - this.renderChart(); - this.resize(); - window.addEventListener( - 'resize', - () => { - requestAnimationFrame(() => this.resize()); - }, - { passive: true } - ); - } - - componentDidUpdate(props) { - const { percent } = this.props; - if (props.percent !== percent) { - // 不加这个会造成绘制缓慢 - this.renderChart('update'); - } - } - - componentWillUnmount() { - cancelAnimationFrame(this.timer); - if (this.node) { - this.node.innerHTML = ''; - } - window.removeEventListener('resize', this.resize); - } - - resize = () => { - if (this.root) { - const { height } = this.props; - const { offsetWidth } = this.root.parentNode; - this.setState({ - radio: offsetWidth < height ? offsetWidth / height : 1, - }); - } - }; - - renderChart(type) { - const { percent, color = '#1890FF' } = this.props; - const data = percent / 100; - const self = this; - cancelAnimationFrame(this.timer); - - if (!this.node || (data !== 0 && !data)) { - return; - } - - const canvas = this.node; - const ctx = canvas.getContext('2d'); - const canvasWidth = canvas.width; - const canvasHeight = canvas.height; - const radius = canvasWidth / 2; - const lineWidth = 2; - const cR = radius - lineWidth; - - ctx.beginPath(); - ctx.lineWidth = lineWidth * 2; - - const axisLength = canvasWidth - lineWidth; - const unit = axisLength / 8; - const range = 0.2; // 振幅 - let currRange = range; - const xOffset = lineWidth; - let sp = 0; // 周期偏移量 - let currData = 0; - const waveupsp = 0.005; // 水波上涨速度 - - let arcStack = []; - const bR = radius - lineWidth; - const circleOffset = -(Math.PI / 2); - let circleLock = true; - - for (let i = circleOffset; i < circleOffset + 2 * Math.PI; i += 1 / (8 * Math.PI)) { - arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]); - } - - const cStartPoint = arcStack.shift(); - ctx.strokeStyle = color; - ctx.moveTo(cStartPoint[0], cStartPoint[1]); - - function drawSin() { - ctx.beginPath(); - ctx.save(); - - const sinStack = []; - for (let i = xOffset; i <= xOffset + axisLength; i += 20 / axisLength) { - const x = sp + (xOffset + i) / unit; - const y = Math.sin(x) * currRange; - const dx = i; - const dy = 2 * cR * (1 - currData) + (radius - cR) - unit * y; - - ctx.lineTo(dx, dy); - sinStack.push([dx, dy]); - } - - const startPoint = sinStack.shift(); - - ctx.lineTo(xOffset + axisLength, canvasHeight); - ctx.lineTo(xOffset, canvasHeight); - ctx.lineTo(startPoint[0], startPoint[1]); - - const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight); - gradient.addColorStop(0, '#ffffff'); - gradient.addColorStop(1, color); - ctx.fillStyle = gradient; - ctx.fill(); - ctx.restore(); - } - - function render() { - ctx.clearRect(0, 0, canvasWidth, canvasHeight); - if (circleLock && type !== 'update') { - if (arcStack.length) { - const temp = arcStack.shift(); - ctx.lineTo(temp[0], temp[1]); - ctx.stroke(); - } else { - circleLock = false; - ctx.lineTo(cStartPoint[0], cStartPoint[1]); - ctx.stroke(); - arcStack = null; - - ctx.globalCompositeOperation = 'destination-over'; - ctx.beginPath(); - ctx.lineWidth = lineWidth; - ctx.arc(radius, radius, bR, 0, 2 * Math.PI, 1); - - ctx.beginPath(); - ctx.save(); - ctx.arc(radius, radius, radius - 3 * lineWidth, 0, 2 * Math.PI, 1); - - ctx.restore(); - ctx.clip(); - ctx.fillStyle = color; - } - } else { - if (data >= 0.85) { - if (currRange > range / 4) { - const t = range * 0.01; - currRange -= t; - } - } else if (data <= 0.1) { - if (currRange < range * 1.5) { - const t = range * 0.01; - currRange += t; - } - } else { - if (currRange <= range) { - const t = range * 0.01; - currRange += t; - } - if (currRange >= range) { - const t = range * 0.01; - currRange -= t; - } - } - if (data - currData > 0) { - currData += waveupsp; - } - if (data - currData < 0) { - currData -= waveupsp; - } - - sp += 0.07; - drawSin(); - } - self.timer = requestAnimationFrame(render); - } - render(); - } - - render() { - const { radio } = this.state; - const { percent, title, height } = this.props; - return ( -
    (this.root = n)} - style={{ transform: `scale(${radio})` }} - > -
    - (this.node = n)} - width={height * 2} - height={height * 2} - /> -
    -
    - {title && {title}} -

    {percent}%

    -
    -
    - ); - } -} - -export default WaterWave; diff --git a/src/components/Charts/WaterWave/index.less b/src/components/Charts/WaterWave/index.less deleted file mode 100644 index 2e75f21464..0000000000 --- a/src/components/Charts/WaterWave/index.less +++ /dev/null @@ -1,28 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.waterWave { - position: relative; - display: inline-block; - transform-origin: left; - .text { - position: absolute; - top: 32px; - left: 0; - width: 100%; - text-align: center; - span { - color: @text-color-secondary; - font-size: 14px; - line-height: 22px; - } - h4 { - color: @heading-color; - font-size: 24px; - line-height: 32px; - } - } - .waterWaveCanvasWrapper { - transform: scale(0.5); - transform-origin: 0 0; - } -} diff --git a/src/components/Charts/autoHeight.js b/src/components/Charts/autoHeight.js deleted file mode 100644 index 6ee9e098d3..0000000000 --- a/src/components/Charts/autoHeight.js +++ /dev/null @@ -1,62 +0,0 @@ -/* eslint eqeqeq: 0 */ -import React from 'react'; - -function computeHeight(node) { - const totalHeight = parseInt(getComputedStyle(node).height, 10); - const padding = - parseInt(getComputedStyle(node).paddingTop, 10) + - parseInt(getComputedStyle(node).paddingBottom, 10); - return totalHeight - padding; -} - -function getAutoHeight(n) { - if (!n) { - return 0; - } - - let node = n; - - let height = computeHeight(node); - - while (!height) { - node = node.parentNode; - if (node) { - height = computeHeight(node); - } else { - break; - } - } - - return height; -} - -const autoHeight = () => WrappedComponent => - class extends React.Component { - state = { - computedHeight: 0, - }; - - componentDidMount() { - const { height } = this.props; - if (!height) { - const h = getAutoHeight(this.root); - // eslint-disable-next-line - this.setState({ computedHeight: h }); - } - } - - handleRoot = node => { - this.root = node; - }; - - render() { - const { height } = this.props; - const { computedHeight } = this.state; - const h = height || computedHeight; - return ( -
    {h > 0 && }
    - ); - } - }; - -export default autoHeight; diff --git a/src/components/Charts/bizcharts.d.ts b/src/components/Charts/bizcharts.d.ts deleted file mode 100644 index 0815ffeeff..0000000000 --- a/src/components/Charts/bizcharts.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import * as BizChart from 'bizcharts'; - -export = BizChart; diff --git a/src/components/Charts/bizcharts.js b/src/components/Charts/bizcharts.js deleted file mode 100644 index e08db8d6d2..0000000000 --- a/src/components/Charts/bizcharts.js +++ /dev/null @@ -1,3 +0,0 @@ -import * as BizChart from 'bizcharts'; - -export default BizChart; diff --git a/src/components/Charts/demo/bar.md b/src/components/Charts/demo/bar.md deleted file mode 100644 index 496ed67004..0000000000 --- a/src/components/Charts/demo/bar.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -order: 4 -title: 柱状图 ---- - -通过设置 `x`,`y` 属性,可以快速的构建出一个漂亮的柱状图,各种纬度的关系则是通过自定义的数据展现。 - -```jsx -import { Bar } from 'ant-design-pro/lib/Charts'; - -const salesData = []; -for (let i = 0; i < 12; i += 1) { - salesData.push({ - x: `${i + 1}月`, - y: Math.floor(Math.random() * 1000) + 200, - }); -} - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Charts/demo/chart-card.md b/src/components/Charts/demo/chart-card.md deleted file mode 100644 index 9ba68643a6..0000000000 --- a/src/components/Charts/demo/chart-card.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -order: 1 -title: 图表卡片 ---- - -用于展示图表的卡片容器,可以方便的配合其它图表套件展示丰富信息。 - -```jsx -import { ChartCard, yuan, Field } from 'ant-design-pro/lib/Charts'; -import Trend from 'ant-design-pro/lib/Trend'; -import { Row, Col, Icon, Tooltip } from 'antd'; -import numeral from 'numeral'; - -ReactDOM.render( - - - - - - } - total={() => } - footer={} - contentHeight={46} - > - - 周同比 - - 12% - - - - 日环比 - - 11% - - - - - - - } - action={ - - - - } - total={() => } - footer={} - /> - - - - } - action={ - - - - } - total={() => } - /> - - , - mountNode -); -``` diff --git a/src/components/Charts/demo/gauge.md b/src/components/Charts/demo/gauge.md deleted file mode 100644 index 3671102b60..0000000000 --- a/src/components/Charts/demo/gauge.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -order: 7 -title: 仪表盘 ---- - -仪表盘是一种进度展示方式,可以更直观的展示当前的进展情况,通常也可表示占比。 - -```jsx -import { Gauge } from 'ant-design-pro/lib/Charts'; - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Charts/demo/mini-area.md b/src/components/Charts/demo/mini-area.md deleted file mode 100644 index 4c1484398b..0000000000 --- a/src/components/Charts/demo/mini-area.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -order: 2 -col: 2 -title: 迷你区域图 ---- - -```jsx -import { MiniArea } from 'ant-design-pro/lib/Charts'; -import moment from 'moment'; - -const visitData = []; -const beginDay = new Date().getTime(); -for (let i = 0; i < 20; i += 1) { - visitData.push({ - x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'), - y: Math.floor(Math.random() * 100) + 10, - }); -} - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Charts/demo/mini-bar.md b/src/components/Charts/demo/mini-bar.md deleted file mode 100644 index 2cfaf0fef8..0000000000 --- a/src/components/Charts/demo/mini-bar.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -order: 2 -col: 2 -title: 迷你柱状图 ---- - -迷你柱状图更适合展示简单的区间数据,简洁的表现方式可以很好的减少大数据量的视觉展现压力。 - -```jsx -import { MiniBar } from 'ant-design-pro/lib/Charts'; -import moment from 'moment'; - -const visitData = []; -const beginDay = new Date().getTime(); -for (let i = 0; i < 20; i += 1) { - visitData.push({ - x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'), - y: Math.floor(Math.random() * 100) + 10, - }); -} - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Charts/demo/mini-pie.md b/src/components/Charts/demo/mini-pie.md deleted file mode 100644 index 76cac9f3a3..0000000000 --- a/src/components/Charts/demo/mini-pie.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -order: 6 -title: 迷你饼状图 ---- - -通过简化 `Pie` 属性的设置,可以快速的实现极简的饼状图,可配合 `ChartCard` 组合展现更多业务场景。 - -```jsx -import { Pie } from 'ant-design-pro/lib/Charts'; - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Charts/demo/mini-progress.md b/src/components/Charts/demo/mini-progress.md deleted file mode 100644 index e4368bee17..0000000000 --- a/src/components/Charts/demo/mini-progress.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -order: 3 -title: 迷你进度条 ---- - -```jsx -import { MiniProgress } from 'ant-design-pro/lib/Charts'; - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Charts/demo/mix.md b/src/components/Charts/demo/mix.md deleted file mode 100644 index 92251f9d1f..0000000000 --- a/src/components/Charts/demo/mix.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -order: 0 -title: 图表套件组合展示 ---- - -利用 Ant Design Pro 提供的图表套件,可以灵活组合符合设计规范的图表来满足复杂的业务需求。 - -```jsx -import { ChartCard, Field, MiniArea, MiniBar, MiniProgress } from 'ant-design-pro/lib/Charts'; -import Trend from 'ant-design-pro/lib/Trend'; -import NumberInfo from 'ant-design-pro/lib/NumberInfo'; -import { Row, Col, Icon, Tooltip } from 'antd'; -import numeral from 'numeral'; -import moment from 'moment'; - -const visitData = []; -const beginDay = new Date().getTime(); -for (let i = 0; i < 20; i += 1) { - visitData.push({ - x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'), - y: Math.floor(Math.random() * 100) + 10, - }); -} - -ReactDOM.render( - - - - 本周访问} - total={numeral(12321).format('0,0')} - status="up" - subTotal={17.1} - /> - - - - - - - - } - total={numeral(8846).format('0,0')} - footer={} - contentHeight={46} - > - - - - - - - - } - total="78%" - footer={ -
    - - 周同比 - - 12% - - - - 日环比 - - 11% - - -
    - } - contentHeight={46} - > - -
    - -
    , - mountNode -); -``` diff --git a/src/components/Charts/demo/pie.md b/src/components/Charts/demo/pie.md deleted file mode 100644 index 392a7c2c8b..0000000000 --- a/src/components/Charts/demo/pie.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -order: 5 -title: 饼状图 ---- - -```jsx -import { Pie, yuan } from 'ant-design-pro/lib/Charts'; - -const salesPieData = [ - { - x: '家用电器', - y: 4544, - }, - { - x: '食用酒水', - y: 3321, - }, - { - x: '个护健康', - y: 3113, - }, - { - x: '服饰箱包', - y: 2341, - }, - { - x: '母婴产品', - y: 1231, - }, - { - x: '其他', - y: 1231, - }, -]; - -ReactDOM.render( - ( - now.y + pre, 0)), - }} - /> - )} - data={salesPieData} - valueFormat={val => } - height={294} - />, - mountNode -); -``` diff --git a/src/components/Charts/demo/radar.md b/src/components/Charts/demo/radar.md deleted file mode 100644 index fd14c0374c..0000000000 --- a/src/components/Charts/demo/radar.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -order: 7 -title: 雷达图 ---- - -```jsx -import { Radar, ChartCard } from 'ant-design-pro/lib/Charts'; - -const radarOriginData = [ - { - name: '个人', - ref: 10, - koubei: 8, - output: 4, - contribute: 5, - hot: 7, - }, - { - name: '团队', - ref: 3, - koubei: 9, - output: 6, - contribute: 3, - hot: 1, - }, - { - name: '部门', - ref: 4, - koubei: 1, - output: 6, - contribute: 5, - hot: 7, - }, -]; -const radarData = []; -const radarTitleMap = { - ref: '引用', - koubei: '口碑', - output: '产量', - contribute: '贡献', - hot: '热度', -}; -radarOriginData.forEach(item => { - Object.keys(item).forEach(key => { - if (key !== 'name') { - radarData.push({ - name: item.name, - label: radarTitleMap[key], - value: item[key], - }); - } - }); -}); - -ReactDOM.render( - - - , - mountNode -); -``` diff --git a/src/components/Charts/demo/tag-cloud.md b/src/components/Charts/demo/tag-cloud.md deleted file mode 100644 index 2f0e0e637f..0000000000 --- a/src/components/Charts/demo/tag-cloud.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -order: 9 -title: 标签云 ---- - -标签云是一套相关的标签以及与此相应的权重展示方式,一般典型的标签云有 30 至 150 个标签,而权重影响使用的字体大小或其他视觉效果。 - -```jsx -import { TagCloud } from 'ant-design-pro/lib/Charts'; - -const tags = []; -for (let i = 0; i < 50; i += 1) { - tags.push({ - name: `TagClout-Title-${i}`, - value: Math.floor(Math.random() * 50) + 20, - }); -} - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Charts/demo/timeline-chart.md b/src/components/Charts/demo/timeline-chart.md deleted file mode 100644 index 6146989e69..0000000000 --- a/src/components/Charts/demo/timeline-chart.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -order: 9 -title: 带有时间轴的图表 ---- - -使用 `TimelineChart` 组件可以实现带有时间轴的柱状图展现,而其中的 `x` 属性,则是时间值的指向,默认最多支持同时展现两个指标,分别是 `y1` 和 `y2`。 - -```jsx -import { TimelineChart } from 'ant-design-pro/lib/Charts'; - -const chartData = []; -for (let i = 0; i < 20; i += 1) { - chartData.push({ - x: new Date().getTime() + 1000 * 60 * 30 * i, - y1: Math.floor(Math.random() * 100) + 1000, - y2: Math.floor(Math.random() * 100) + 10, - }); -} - -ReactDOM.render( - , - mountNode -); -``` diff --git a/src/components/Charts/demo/waterwave.md b/src/components/Charts/demo/waterwave.md deleted file mode 100644 index 718cd2a095..0000000000 --- a/src/components/Charts/demo/waterwave.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -order: 8 -title: 水波图 ---- - -水波图是一种比例的展示方式,可以更直观的展示关键值的占比。 - -```jsx -import { WaterWave } from 'ant-design-pro/lib/Charts'; - -ReactDOM.render( -
    - -
    , - mountNode -); -``` diff --git a/src/components/Charts/index.d.ts b/src/components/Charts/index.d.ts deleted file mode 100644 index 57f1d52728..0000000000 --- a/src/components/Charts/index.d.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as numeral from 'numeral'; -import { default as Bar } from './Bar'; -import { default as ChartCard } from './ChartCard'; -import { default as Field } from './Field'; -import { default as Gauge } from './Gauge'; -import { default as MiniArea } from './MiniArea'; -import { default as MiniBar } from './MiniBar'; -import { default as MiniProgress } from './MiniProgress'; -import { default as Pie } from './Pie'; -import { default as Radar } from './Radar'; -import { default as TagCloud } from './TagCloud'; -import { default as TimelineChart } from './TimelineChart'; -import { default as WaterWave } from './WaterWave'; - -declare const yuan: (value: number | string) => string; - -declare const Charts: { - yuan: (value: number | string) => string; - Bar: Bar; - Pie: Pie; - Gauge: Gauge; - Radar: Radar; - MiniBar: MiniBar; - MiniArea: MiniArea; - MiniProgress: MiniProgress; - ChartCard: ChartCard; - Field: Field; - WaterWave: WaterWave; - TagCloud: TagCloud; - TimelineChart: TimelineChart; -}; - -export { - Charts as default, - yuan, - Bar, - Pie, - Gauge, - Radar, - MiniBar, - MiniArea, - MiniProgress, - ChartCard, - Field, - WaterWave, - TagCloud, - TimelineChart, -}; diff --git a/src/components/Charts/index.js b/src/components/Charts/index.js deleted file mode 100644 index 294eeb65f4..0000000000 --- a/src/components/Charts/index.js +++ /dev/null @@ -1,48 +0,0 @@ -import numeral from 'numeral'; -import ChartCard from './ChartCard'; -import Field from './Field'; -import Bar from './Bar'; -import Pie from './Pie'; -import Radar from './Radar'; -import Gauge from './Gauge'; -import MiniArea from './MiniArea'; -import MiniBar from './MiniBar'; -import MiniProgress from './MiniProgress'; -import WaterWave from './WaterWave'; -import TagCloud from './TagCloud'; -import TimelineChart from './TimelineChart'; - -const yuan = val => `¥ ${numeral(val).format('0,0')}`; - -const Charts = { - yuan, - Bar, - Pie, - Gauge, - Radar, - MiniBar, - MiniArea, - MiniProgress, - ChartCard, - Field, - WaterWave, - TagCloud, - TimelineChart, -}; - -export { - Charts as default, - yuan, - Bar, - Pie, - Gauge, - Radar, - MiniBar, - MiniArea, - MiniProgress, - ChartCard, - Field, - WaterWave, - TagCloud, - TimelineChart, -}; diff --git a/src/components/Charts/index.less b/src/components/Charts/index.less deleted file mode 100644 index 190428bc80..0000000000 --- a/src/components/Charts/index.less +++ /dev/null @@ -1,19 +0,0 @@ -.miniChart { - position: relative; - width: 100%; - .chartContent { - position: absolute; - bottom: -28px; - width: 100%; - > div { - margin: 0 -5px; - overflow: hidden; - } - } - .chartLoading { - position: absolute; - top: 16px; - left: 50%; - margin-left: -7px; - } -} diff --git a/src/components/Charts/index.md b/src/components/Charts/index.md deleted file mode 100644 index 3456bc1989..0000000000 --- a/src/components/Charts/index.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: Charts -subtitle: 图表 -order: 2 -cols: 2 ---- - -Ant Design Pro 提供的业务中常用的图表类型,都是基于 [G2](https://antv.alipay.com/g2/doc/index.html) 按照 Ant Design 图表规范封装,需要注意的是 Ant Design Pro 的图表组件以套件形式提供,可以任意组合实现复杂的业务需求。 - -因为结合了 Ant Design 的标准设计,本着极简的设计思想以及开箱即用的理念,简化了大量 API 配置,所以如果需要灵活定制图表,可以参考 Ant Design Pro 图表实现,自行基于 [G2](https://antv.alipay.com/g2/doc/index.html) 封装图表组件使用。 - -## API - -### ChartCard - -| 参数 | 说明 | 类型 | 默认值 | -| ------------- | ------------ | ------------------------------- | ------ | -| title | 卡片标题 | ReactNode\|string | - | -| action | 卡片操作 | ReactNode | - | -| total | 数据总量 | ReactNode \| number \| function | - | -| footer | 卡片底部 | ReactNode | - | -| contentHeight | 内容区域高度 | number | - | -| avatar | 右侧图标 | React.ReactNode | - | - -### MiniBar - -| 参数 | 说明 | 类型 | 默认值 | -| ------ | -------- | ------------- | --------- | -| color | 图表颜色 | string | `#1890FF` | -| height | 图表高度 | number | - | -| data | 数据 | array<{x, y}> | - | - -### MiniArea - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| color | 图表颜色 | string | `rgba(24, 144, 255, 0.2)` | -| borderColor | 图表边颜色 | string | `#1890FF` | -| height | 图表高度 | number | - | -| line | 是否显示描边 | boolean | false | -| animate | 是否显示动画 | boolean | true | -| xAxis | [x 轴配置](http://antvis.github.io/g2/doc/tutorial/start/axis.html) | object | - | -| yAxis | [y 轴配置](http://antvis.github.io/g2/doc/tutorial/start/axis.html) | object | - | -| data | 数据 | array<{x, y}> | - | - -### MiniProgress - -| 参数 | 说明 | 类型 | 默认值 | -| ----------- | ---------- | ------ | ------ | -| target | 目标比例 | number | - | -| color | 进度条颜色 | string | - | -| strokeWidth | 进度条高度 | number | - | -| percent | 进度比例 | number | - | - -### Bar - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| title | 图表标题 | ReactNode\|string | - | -| color | 图表颜色 | string | `rgba(24, 144, 255, 0.85)` | -| padding | 图表内部间距 | [array](https://github.com/alibaba/BizCharts/blob/master/doc/api/chart.md#7padding-object--number--array-) | `'auto'` | -| height | 图表高度 | number | - | -| data | 数据 | array<{x, y}> | - | -| autoLabel | 在宽度不足时,自动隐藏 x 轴的 label | boolean | `true` | - -### Pie - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| animate | 是否显示动画 | boolean | true | -| color | 图表颜色 | string | `rgba(24, 144, 255, 0.85)` | -| height | 图表高度 | number | - | -| hasLegend | 是否显示 legend | boolean | `false` | -| padding | 图表内部间距 | [array](https://github.com/alibaba/BizCharts/blob/master/doc/api/chart.md#7padding-object--number--array-) | `'auto'` | -| percent | 占比 | number | - | -| tooltip | 是否显示 tooltip | boolean | true | -| valueFormat | 显示值的格式化函数 | function | - | -| title | 图表标题 | ReactNode\|string | - | -| subTitle | 图表子标题 | ReactNode\|string | - | -| total | 图标中央的总数 | string | function | - | - -### Radar - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| title | 图表标题 | ReactNode\|string | - | -| height | 图表高度 | number | - | -| hasLegend | 是否显示 legend | boolean | `false` | -| padding | 图表内部间距 | [array](https://github.com/alibaba/BizCharts/blob/master/doc/api/chart.md#7padding-object--number--array-) | `'auto'` | -| data | 图标数据 | array<{name,label,value}> | - | - -### Gauge - -| 参数 | 说明 | 类型 | 默认值 | -| ------- | ------------ | ----------------- | --------- | -| title | 图表标题 | ReactNode\|string | - | -| height | 图表高度 | number | - | -| color | 图表颜色 | string | `#2F9CFF` | -| bgColor | 图表背景颜色 | string | `#F0F2F5` | -| percent | 进度比例 | number | - | - -### WaterWave - -| 参数 | 说明 | 类型 | 默认值 | -| ------- | -------- | ----------------- | --------- | -| title | 图表标题 | ReactNode\|string | - | -| height | 图表高度 | number | - | -| color | 图表颜色 | string | `#1890FF` | -| percent | 进度比例 | number | - | - -### TagCloud - -| 参数 | 说明 | 类型 | 默认值 | -| ------ | ------ | ------------------- | ------ | -| data | 标题 | Array | - | -| height | 高度值 | number | - | - -### TimelineChart - -| 参数 | 说明 | 类型 | 默认值 | -| -------- | -------- | ------------------------------------ | ------ | -| data | 标题 | Array | - | -| titleMap | 指标别名 | Object{y1: '客流量', y2: '支付笔数'} | - | -| height | 高度值 | number | 400 | - -### Field - -| 参数 | 说明 | 类型 | 默认值 | -| ----- | ---- | ----------------- | ------ | -| label | 标题 | ReactNode\|string | - | -| value | 值 | ReactNode\|string | - | diff --git a/src/components/CopyBlock/index.less b/src/components/CopyBlock/index.less new file mode 100644 index 0000000000..83d899a141 --- /dev/null +++ b/src/components/CopyBlock/index.less @@ -0,0 +1,29 @@ +.copy-block { + position: fixed; + right: 80px; + bottom: 40px; + z-index: 99; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + font-size: 20px; + background: #fff; + border-radius: 40px; + box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), + 0 1px 10px 0 rgba(0, 0, 0, 0.12); + cursor: pointer; +} + +.copy-block-view { + position: relative; + .copy-block-code { + display: inline-block; + margin: 0 0.2em; + padding: 0.2em 0.4em 0.1em; + font-size: 85%; + border-radius: 3px; + } +} diff --git a/src/components/CopyBlock/index.tsx b/src/components/CopyBlock/index.tsx new file mode 100644 index 0000000000..682e77cfa2 --- /dev/null +++ b/src/components/CopyBlock/index.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import { Icon, Typography, Popover } from 'antd'; +import styles from './index.less'; +import { connect } from 'dva'; +import * as H from 'history'; +import { FormattedMessage } from 'umi-plugin-react/locale'; + +const firstUpperCase = (pathString: string) => { + return pathString + .replace('.', '') + .split(/\/|\-/) + .map(s => s.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase())) + .filter(s => s) + .join(''); +}; +const BlockCodeView: React.SFC<{ + url: string; +}> = ({ url }) => { + const blockUrl = `npx umi block add ant-design-pro/${firstUpperCase(url)} --path=${url}`; + return ( +
    + + {blockUrl} + +
    + ); +}; + +type RoutingType = { location: H.Location }; + +export default connect(({ routing }: { routing: RoutingType }) => ({ + location: routing.location, +}))(({ location }: RoutingType) => { + const url = location.pathname; + return ( + } + placement="topLeft" + content={} + trigger="click" + > +
    + +
    +
    + ); +}); diff --git a/src/components/CountDown/demo/simple.md b/src/components/CountDown/demo/simple.md deleted file mode 100644 index c0e23be260..0000000000 --- a/src/components/CountDown/demo/simple.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -order: 0 -title: - zh-CN: 基本 - en-US: Basic ---- - -## zh-CN - -简单的倒计时组件使用。 - -## en-US - -The simplest usage. - -```jsx -import CountDown from 'ant-design-pro/lib/CountDown'; - -const targetTime = new Date().getTime() + 3900000; - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/CountDown/index.d.ts b/src/components/CountDown/index.d.ts deleted file mode 100644 index af658e3f6c..0000000000 --- a/src/components/CountDown/index.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -export interface ICountDownProps { - format?: (time: number) => void; - target: Date | number; - onEnd?: () => void; - style?: React.CSSProperties; -} - -export default class CountDown extends React.Component {} diff --git a/src/components/CountDown/index.en-US.md b/src/components/CountDown/index.en-US.md deleted file mode 100644 index 19bbe275c7..0000000000 --- a/src/components/CountDown/index.en-US.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: CountDown -cols: 1 -order: 3 ---- - -Simple CountDown Component. - -## API - -| Property | Description | Type | Default | -| -------- | ----------------------------- | -------------- | ------- | -| format | Formatter of time | Function(time) | | -| target | Target time | Date | - | -| onEnd | Countdown to the end callback | funtion | - | diff --git a/src/components/CountDown/index.js b/src/components/CountDown/index.js deleted file mode 100644 index 7565bd82da..0000000000 --- a/src/components/CountDown/index.js +++ /dev/null @@ -1,121 +0,0 @@ -import React, { Component } from 'react'; - -function fixedZero(val) { - return val * 1 < 10 ? `0${val}` : val; -} -const initTime = props => { - let lastTime = 0; - let targetTime = 0; - try { - if (Object.prototype.toString.call(props.target) === '[object Date]') { - targetTime = props.target.getTime(); - } else { - targetTime = new Date(props.target).getTime(); - } - } catch (e) { - throw new Error('invalid target prop', e); - } - - lastTime = targetTime - new Date().getTime(); - return { - lastTime: lastTime < 0 ? 0 : lastTime, - }; -}; - -class CountDown extends Component { - timer = 0; - - interval = 1000; - - constructor(props) { - super(props); - const { lastTime } = initTime(props); - this.state = { - lastTime, - }; - } - - static getDerivedStateFromProps(nextProps, preState) { - const { lastTime } = initTime(nextProps); - if (preState.lastTime !== lastTime) { - return { - lastTime, - }; - } - return null; - } - - componentDidMount() { - this.tick(); - } - - componentDidUpdate(prevProps) { - const { target } = this.props; - if (target !== prevProps.target) { - clearTimeout(this.timer); - this.tick(); - } - } - - componentWillUnmount() { - clearTimeout(this.timer); - } - - // defaultFormat = time => ( - // {moment(time).format('hh:mm:ss')} - // ); - defaultFormat = time => { - const hours = 60 * 60 * 1000; - const minutes = 60 * 1000; - - const h = Math.floor(time / hours); - const m = Math.floor((time - h * hours) / minutes); - const s = Math.floor((time - h * hours - m * minutes) / 1000); - return ( - - {fixedZero(h)}:{fixedZero(m)}:{fixedZero(s)} - - ); - }; - - tick = () => { - const { onEnd } = this.props; - let { lastTime } = this.state; - - this.timer = setTimeout(() => { - if (lastTime < this.interval) { - clearTimeout(this.timer); - this.setState( - { - lastTime: 0, - }, - () => { - if (onEnd) { - onEnd(); - } - } - ); - } else { - lastTime -= this.interval; - this.setState( - { - lastTime, - }, - () => { - this.tick(); - } - ); - } - }, this.interval); - }; - - render() { - const { format = this.defaultFormat, onEnd, ...rest } = this.props; - const { lastTime } = this.state; - const result = format(lastTime); - - return {result}; - } -} - -export default CountDown; diff --git a/src/components/CountDown/index.zh-CN.md b/src/components/CountDown/index.zh-CN.md deleted file mode 100644 index 8753928998..0000000000 --- a/src/components/CountDown/index.zh-CN.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: CountDown -subtitle: 倒计时 -cols: 1 -order: 3 ---- - -倒计时组件。 - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| ------ | -------------- | -------------- | ------ | -| format | 时间格式化显示 | Function(time) | | -| target | 目标时间 | Date | - | -| onEnd | 倒计时结束回调 | funtion | - | diff --git a/src/components/DescriptionList/Description.d.ts b/src/components/DescriptionList/Description.d.ts deleted file mode 100644 index 41c0497075..0000000000 --- a/src/components/DescriptionList/Description.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import { ColProps } from 'antd/es/col'; - -export interface DescriptionProps extends ColProps { - column?: number; - key?: string | number; - style?: React.CSSProperties; - term?: React.ReactNode; -} - -export default class Description extends React.Component {} diff --git a/src/components/DescriptionList/Description.js b/src/components/DescriptionList/Description.js deleted file mode 100644 index fce9fd3cb7..0000000000 --- a/src/components/DescriptionList/Description.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Col } from 'antd'; -import styles from './index.less'; -import responsive from './responsive'; - -const Description = ({ term, column, children, ...restProps }) => ( - - {term &&
    {term}
    } - {children !== null && children !== undefined &&
    {children}
    } - -); - -Description.defaultProps = { - term: '', -}; - -Description.propTypes = { - term: PropTypes.node, -}; - -export default Description; diff --git a/src/components/DescriptionList/DescriptionList.js b/src/components/DescriptionList/DescriptionList.js deleted file mode 100644 index 84bdbd79d3..0000000000 --- a/src/components/DescriptionList/DescriptionList.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import classNames from 'classnames'; -import { Row } from 'antd'; -import styles from './index.less'; - -const DescriptionList = ({ - className, - title, - col = 3, - layout = 'horizontal', - gutter = 32, - children, - size, - ...restProps -}) => { - const clsString = classNames(styles.descriptionList, styles[layout], className, { - [styles.small]: size === 'small', - [styles.large]: size === 'large', - }); - const column = col > 4 ? 4 : col; - return ( -
    - {title ?
    {title}
    : null} - - {React.Children.map(children, child => - child ? React.cloneElement(child, { column }) : child - )} - -
    - ); -}; - -export default DescriptionList; diff --git a/src/components/DescriptionList/demo/basic.md b/src/components/DescriptionList/demo/basic.md deleted file mode 100644 index e45c110340..0000000000 --- a/src/components/DescriptionList/demo/basic.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -order: 0 -title: - zh-CN: 基本 - en-US: Basic ---- - -## zh-CN - -基本描述列表。 - -## en-US - -Basic DescriptionList. - -```jsx -import DescriptionList from 'ant-design-pro/lib/DescriptionList'; - -const { Description } = DescriptionList; - -ReactDOM.render( - - - A free, open source, cross-platform, graphical web browser developed by the Mozilla - Corporation and hundreds of volunteers. - - - A free, open source, cross-platform, graphical web browser developed by the Mozilla - Corporation and hundreds of volunteers. - - - A free, open source, cross-platform, graphical web browser developed by the Mozilla - Corporation and hundreds of volunteers. - - , - mountNode -); -``` diff --git a/src/components/DescriptionList/demo/vertical.md b/src/components/DescriptionList/demo/vertical.md deleted file mode 100644 index 8bdd3dc034..0000000000 --- a/src/components/DescriptionList/demo/vertical.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -order: 1 -title: - zh-CN: 垂直型 - en-US: Vertical ---- - -## zh-CN - -垂直布局。 - -## en-US - -Vertical layout. - -```jsx -import DescriptionList from 'ant-design-pro/lib/DescriptionList'; - -const { Description } = DescriptionList; - -ReactDOM.render( - - - A free, open source, cross-platform, graphical web browser developed by the Mozilla - Corporation and hundreds of volunteers. - - - A free, open source, cross-platform, graphical web browser developed by the Mozilla - Corporation and hundreds of volunteers. - - - A free, open source, cross-platform, graphical web browser developed by the Mozilla - Corporation and hundreds of volunteers. - - , - mountNode -); -``` diff --git a/src/components/DescriptionList/index.d.ts b/src/components/DescriptionList/index.d.ts deleted file mode 100644 index c0bb071c5a..0000000000 --- a/src/components/DescriptionList/index.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import Description, { DescriptionProps } from './Description'; - -export interface DescriptionListProps { - className?: string; - col?: number; - description?: DescriptionProps[]; - gutter?: number; - layout?: 'horizontal' | 'vertical'; - size?: 'large' | 'small'; - style?: React.CSSProperties; - title?: React.ReactNode; -} - -export default class DescriptionList extends React.Component { - public static Description: typeof Description; -} diff --git a/src/components/DescriptionList/index.en-US.md b/src/components/DescriptionList/index.en-US.md deleted file mode 100644 index 9b956a0f80..0000000000 --- a/src/components/DescriptionList/index.en-US.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: DescriptionList -cols: 1 -order: 4 ---- - -Groups display multiple read-only fields, which are common to informational displays on detail pages. - -## API - -### DescriptionList - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| layout | type of layout | Enum{'horizontal', 'vertical'} | 'horizontal' | -| 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 | -| title | title | ReactNode | - | -| gutter | specify the distance between two items, unit is `px` | number | 32 | -| size | size of list | Enum{'large', 'small'} | - | - -#### Responsive Rules - -| Window Width | Columns Number | -| ------------ | ------------------- | -| `≥768px` | `col` | -| `≥576px` | `col < 2 ? col : 2` | -| `<576px` | `1` | - -### DescriptionList.Description - -| Property | Description | Type | Default | -| -------- | ----------- | --------- | ------- | -| term | item title | ReactNode | - | diff --git a/src/components/DescriptionList/index.js b/src/components/DescriptionList/index.js deleted file mode 100644 index 357f479fd5..0000000000 --- a/src/components/DescriptionList/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import DescriptionList from './DescriptionList'; -import Description from './Description'; - -DescriptionList.Description = Description; -export default DescriptionList; diff --git a/src/components/DescriptionList/index.less b/src/components/DescriptionList/index.less deleted file mode 100644 index c3cf8e69e7..0000000000 --- a/src/components/DescriptionList/index.less +++ /dev/null @@ -1,92 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.descriptionList { - // offset the padding-bottom of last row - :global { - .ant-row { - margin-bottom: -16px; - overflow: hidden; - } - } - // fix margin top error of following descriptionList - & + & { - :global { - .ant-row { - margin-top: 16px; - } - } - } - - .title { - margin-bottom: 16px; - color: @heading-color; - font-weight: 500; - font-size: 14px; - } - - .term { - display: table-cell; - padding-bottom: 16px; - color: @heading-color; - // Line-height is 22px IE dom height will calculate error - line-height: 20px; - white-space: nowrap; - - &::after { - position: relative; - top: -0.5px; - margin: 0 8px 0 2px; - content: ':'; - } - } - - .detail { - display: table-cell; - width: 100%; - padding-bottom: 16px; - color: @text-color; - line-height: 20px; - } - - &.small { - // offset the padding-bottom of last row - :global { - .ant-row { - margin-bottom: -8px; - } - } - // fix margin top error of following descriptionList - & + .descriptionList { - :global { - .ant-row { - margin-top: 8px; - } - } - } - .title { - margin-bottom: 12px; - color: @text-color; - } - .term, - .detail { - padding-bottom: 8px; - } - } - - &.large { - .title { - font-size: 16px; - } - } - - &.vertical { - .term { - display: block; - padding-bottom: 8px; - } - - .detail { - display: block; - } - } -} diff --git a/src/components/DescriptionList/index.zh-CN.md b/src/components/DescriptionList/index.zh-CN.md deleted file mode 100644 index bc7028a690..0000000000 --- a/src/components/DescriptionList/index.zh-CN.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: DescriptionList -subtitle: 描述列表 -cols: 1 -order: 4 ---- - -成组展示多个只读字段,常见于详情页的信息展示。 - -## API - -### DescriptionList - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| layout | 布局方式 | Enum{'horizontal', 'vertical'} | 'horizontal' | -| col | 指定信息最多分几列展示,最终一行几列由 col 配置结合[响应式规则](/components/DescriptionList#响应式规则)决定 | number(0 < col <= 4) | 3 | -| title | 列表标题 | ReactNode | - | -| gutter | 列表项间距,单位为 `px` | number | 32 | -| size | 列表型号 | Enum{'large', 'small'} | - | - -#### 响应式规则 - -| 窗口宽度 | 展示列数 | -| -------- | ------------------- | -| `≥768px` | `col` | -| `≥576px` | `col < 2 ? col : 2` | -| `<576px` | `1` | - -### DescriptionList.Description - -| 参数 | 说明 | 类型 | 默认值 | -| ---- | ---------- | --------- | ------ | -| term | 列表项标题 | ReactNode | - | diff --git a/src/components/DescriptionList/responsive.js b/src/components/DescriptionList/responsive.js deleted file mode 100644 index a5aa73f781..0000000000 --- a/src/components/DescriptionList/responsive.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - 1: { xs: 24 }, - 2: { xs: 24, sm: 12 }, - 3: { xs: 24, sm: 12, md: 8 }, - 4: { xs: 24, sm: 12, md: 6 }, -}; diff --git a/src/components/EditableItem/index.d.ts b/src/components/EditableItem/index.d.ts deleted file mode 100644 index fc69b2748f..0000000000 --- a/src/components/EditableItem/index.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -export interface EditableItemProps { - onChange?: (value?: string | string[] | number) => void; -} - -export default class EditableItem extends React.Component {} diff --git a/src/components/EditableItem/index.js b/src/components/EditableItem/index.js deleted file mode 100644 index 40034d0ac9..0000000000 --- a/src/components/EditableItem/index.js +++ /dev/null @@ -1,50 +0,0 @@ -import React, { PureComponent } from 'react'; -import { Input, Icon } from 'antd'; -import styles from './index.less'; - -export default class EditableItem extends PureComponent { - constructor(props) { - super(props); - this.state = { - value: props.value, - editable: false, - }; - } - - handleChange = e => { - const { value } = e.target; - this.setState({ value }); - }; - - check = () => { - this.setState({ editable: false }); - const { value } = this.state; - const { onChange } = this.props; - if (onChange) { - onChange(value); - } - }; - - edit = () => { - this.setState({ editable: true }); - }; - - render() { - const { value, editable } = this.state; - return ( -
    - {editable ? ( -
    - - -
    - ) : ( -
    - {value || ' '} - -
    - )} -
    - ); - } -} diff --git a/src/components/EditableItem/index.less b/src/components/EditableItem/index.less deleted file mode 100644 index 7fdf337061..0000000000 --- a/src/components/EditableItem/index.less +++ /dev/null @@ -1,25 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.editableItem { - display: table; - width: 100%; - margin-top: (@font-size-base * @line-height-base - @input-height-base) / 2; - line-height: @input-height-base; - - .wrapper { - display: table-row; - - & > * { - display: table-cell; - } - - & > *:first-child { - width: 85%; - } - - .icon { - text-align: right; - cursor: pointer; - } - } -} diff --git a/src/components/EditableLinkGroup/index.d.ts b/src/components/EditableLinkGroup/index.d.ts deleted file mode 100644 index 07a42abecd..0000000000 --- a/src/components/EditableLinkGroup/index.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; - -export interface EditableLinkGroupProps { - links: any[]; - onAdd: () => void; - linkElement: string; -} - -export default class EditableLinkGroup extends React.Component {} diff --git a/src/components/EditableLinkGroup/index.js b/src/components/EditableLinkGroup/index.js deleted file mode 100644 index ae3d93c712..0000000000 --- a/src/components/EditableLinkGroup/index.js +++ /dev/null @@ -1,46 +0,0 @@ -import React, { PureComponent, createElement } from 'react'; -import PropTypes from 'prop-types'; -import { Button } from 'antd'; -import styles from './index.less'; - -// TODO: 添加逻辑 - -class EditableLinkGroup extends PureComponent { - static propTypes = { - links: PropTypes.array, - onAdd: PropTypes.func, - linkElement: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), - }; - - static defaultProps = { - links: [], - onAdd: () => {}, - linkElement: 'a', - }; - - render() { - const { links, linkElement, onAdd } = this.props; - return ( -
    - {links.map(link => - createElement( - linkElement, - { - key: `linkGroup-item-${link.id || link.title}`, - to: link.href, - href: link.href, - }, - link.title - ) - )} - { - - } -
    - ); - } -} - -export default EditableLinkGroup; diff --git a/src/components/EditableLinkGroup/index.less b/src/components/EditableLinkGroup/index.less deleted file mode 100644 index ba53315d9a..0000000000 --- a/src/components/EditableLinkGroup/index.less +++ /dev/null @@ -1,16 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.linkGroup { - padding: 20px 0 8px 24px; - font-size: 0; - & > a { - display: inline-block; - width: 25%; - margin-bottom: 13px; - color: @text-color; - font-size: @font-size-base; - &:hover { - color: @primary-color; - } - } -} diff --git a/src/components/Ellipsis/demo/line.md b/src/components/Ellipsis/demo/line.md deleted file mode 100644 index a9be7c2c25..0000000000 --- a/src/components/Ellipsis/demo/line.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -order: 1 -title: - zh-CN: 按照行数省略 - en-US: Truncate according to the number of rows ---- - -## zh-CN - -通过设置 `lines` 属性指定最大行数,如果超过这个行数的文本会自动截取。但是在这种模式下所有 `children` 将会被转换成纯文本。 - -并且注意在这种模式下,外容器需要有指定的宽度(或设置自身宽度)。 - -## en-US - -`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. - -Also note that, in this mode, the outer container needs to have a specified width (or set its own width). - -```jsx -import Ellipsis from 'ant-design-pro/lib/Ellipsis'; - -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. -

    -); - -ReactDOM.render( -
    - - {article} - -
    , - mountNode -); -``` diff --git a/src/components/Ellipsis/demo/number.md b/src/components/Ellipsis/demo/number.md deleted file mode 100644 index cc7aa3e7be..0000000000 --- a/src/components/Ellipsis/demo/number.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -order: 0 -title: - zh-CN: 按照字符数省略 - en-US: Truncate according to the number of character ---- - -## zh-CN - -通过设置 `length` 属性指定文本最长长度,如果超过这个长度会自动截取。 - -## en-US - -`length` attribute specifies the maximum length where the text will automatically be truncated when exceeded. - -```jsx -import Ellipsis from 'ant-design-pro/lib/Ellipsis'; - -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.'; - -ReactDOM.render( -
    - {article} -

    Show Tooltip

    - - {article} - -
    , - mountNode -); -``` diff --git a/src/components/Ellipsis/index.d.ts b/src/components/Ellipsis/index.d.ts deleted file mode 100644 index 075fa789a4..0000000000 --- a/src/components/Ellipsis/index.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { TooltipProps } from 'antd/lib/tooltip'; - -export interface EllipsisTooltipProps extends TooltipProps { - title?: undefined; - overlayStyle?: undefined; -} - -export interface EllipsisProps { - tooltip?: boolean | EllipsisTooltipProps; - length?: number; - lines?: number; - style?: React.CSSProperties; - className?: string; - fullWidthRecognition?: boolean; -} - -export function getStrFullLength(str: string): number; -export function cutStrByFullLength(str: string, maxLength: number): string; - -export default class Ellipsis extends React.Component {} diff --git a/src/components/Ellipsis/index.en-US.md b/src/components/Ellipsis/index.en-US.md deleted file mode 100644 index 8098873044..0000000000 --- a/src/components/Ellipsis/index.en-US.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: Ellipsis -cols: 1 -order: 10 ---- - -When the text is too long, the Ellipsis automatically shortens it according to its length or the maximum number of lines. - -## API - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| tooltip | tooltip for showing the full text content when hovering over | boolean | - | -| length | maximum number of characters in the text before being truncated | number | - | -| lines | maximum number of rows in the text before being truncated | number | `1` | -| fullWidthRecognition | whether consider full-width character length as 2 when calculate string length | boolean | - | diff --git a/src/components/Ellipsis/index.js b/src/components/Ellipsis/index.js deleted file mode 100644 index de700b74b1..0000000000 --- a/src/components/Ellipsis/index.js +++ /dev/null @@ -1,270 +0,0 @@ -import React, { Component } from 'react'; -import { Tooltip } from 'antd'; -import classNames from 'classnames'; -import styles from './index.less'; - -/* eslint react/no-did-mount-set-state: 0 */ -/* eslint no-param-reassign: 0 */ - -const isSupportLineClamp = document.body.style.webkitLineClamp !== undefined; - -const TooltipOverlayStyle = { - overflowWrap: 'break-word', - wordWrap: 'break-word', -}; - -export const getStrFullLength = (str = '') => - str.split('').reduce((pre, cur) => { - const charCode = cur.charCodeAt(0); - if (charCode >= 0 && charCode <= 128) { - return pre + 1; - } - return pre + 2; - }, 0); - -export const cutStrByFullLength = (str = '', maxLength) => { - let showLength = 0; - return str.split('').reduce((pre, cur) => { - const charCode = cur.charCodeAt(0); - if (charCode >= 0 && charCode <= 128) { - showLength += 1; - } else { - showLength += 2; - } - if (showLength <= maxLength) { - return pre + cur; - } - return pre; - }, ''); -}; - -const getTooltip = ({ tooltip, overlayStyle, title, children }) => { - if (tooltip) { - const props = tooltip === true ? { overlayStyle, title } : { ...tooltip, overlayStyle, title }; - return {children}; - } - return children; -}; - -const EllipsisText = ({ text, length, tooltip, fullWidthRecognition, ...other }) => { - if (typeof text !== 'string') { - throw new Error('Ellipsis children must be string.'); - } - const textLength = fullWidthRecognition ? getStrFullLength(text) : text.length; - if (textLength <= length || length < 0) { - return {text}; - } - const tail = '...'; - let displayText; - if (length - tail.length <= 0) { - displayText = ''; - } else { - displayText = fullWidthRecognition ? cutStrByFullLength(text, length) : text.slice(0, length); - } - - const spanAttrs = tooltip ? {} : { ...other }; - return getTooltip({ - tooltip, - overlayStyle: TooltipOverlayStyle, - title: text, - children: ( - - {displayText} - {tail} - - ), - }); -}; - -export default class Ellipsis extends Component { - state = { - text: '', - targetCount: 0, - }; - - componentDidMount() { - if (this.node) { - this.computeLine(); - } - } - - componentDidUpdate(perProps) { - const { lines } = this.props; - if (lines !== perProps.lines) { - this.computeLine(); - } - } - - computeLine = () => { - const { lines } = this.props; - if (lines && !isSupportLineClamp) { - const text = this.shadowChildren.innerText || this.shadowChildren.textContent; - const lineHeight = parseInt(getComputedStyle(this.root).lineHeight, 10); - const targetHeight = lines * lineHeight; - this.content.style.height = `${targetHeight}px`; - const totalHeight = this.shadowChildren.offsetHeight; - const shadowNode = this.shadow.firstChild; - - if (totalHeight <= targetHeight) { - this.setState({ - text, - targetCount: text.length, - }); - return; - } - - // bisection - const len = text.length; - const mid = Math.ceil(len / 2); - - const count = this.bisection(targetHeight, mid, 0, len, text, shadowNode); - - this.setState({ - text, - targetCount: count, - }); - } - }; - - bisection = (th, m, b, e, text, shadowNode) => { - const suffix = '...'; - let mid = m; - let end = e; - let begin = b; - shadowNode.innerHTML = text.substring(0, mid) + suffix; - let sh = shadowNode.offsetHeight; - - if (sh <= th) { - shadowNode.innerHTML = text.substring(0, mid + 1) + suffix; - sh = shadowNode.offsetHeight; - if (sh > th || mid === begin) { - return mid; - } - begin = mid; - if (end - begin === 1) { - mid = 1 + begin; - } else { - mid = Math.floor((end - begin) / 2) + begin; - } - return this.bisection(th, mid, begin, end, text, shadowNode); - } - if (mid - 1 < 0) { - return mid; - } - shadowNode.innerHTML = text.substring(0, mid - 1) + suffix; - sh = shadowNode.offsetHeight; - if (sh <= th) { - return mid - 1; - } - end = mid; - mid = Math.floor((end - begin) / 2) + begin; - return this.bisection(th, mid, begin, end, text, shadowNode); - }; - - handleRoot = n => { - this.root = n; - }; - - handleContent = n => { - this.content = n; - }; - - handleNode = n => { - this.node = n; - }; - - handleShadow = n => { - this.shadow = n; - }; - - handleShadowChildren = n => { - this.shadowChildren = n; - }; - - render() { - const { text, targetCount } = this.state; - const { - children, - lines, - length, - className, - tooltip, - fullWidthRecognition, - ...restProps - } = this.props; - - const cls = classNames(styles.ellipsis, className, { - [styles.lines]: lines && !isSupportLineClamp, - [styles.lineClamp]: lines && isSupportLineClamp, - }); - - if (!lines && !length) { - return ( - - {children} - - ); - } - - // length - if (!lines) { - return ( - - ); - } - - const id = `antd-pro-ellipsis-${`${new Date().getTime()}${Math.floor(Math.random() * 100)}`}`; - - // support document.body.style.webkitLineClamp - if (isSupportLineClamp) { - const style = `#${id}{-webkit-line-clamp:${lines};-webkit-box-orient: vertical;}`; - - const node = ( -
    - - {children} -
    - ); - - return getTooltip({ - tooltip, - overlayStyle: TooltipOverlayStyle, - title: children, - children: node, - }); - } - - const childNode = ( - - {targetCount > 0 && text.substring(0, targetCount)} - {targetCount > 0 && targetCount < text.length && '...'} - - ); - - return ( -
    -
    - {getTooltip({ - tooltip, - overlayStyle: TooltipOverlayStyle, - title: text, - children: childNode, - })} -
    - {children} -
    -
    - {text} -
    -
    -
    - ); - } -} diff --git a/src/components/Ellipsis/index.less b/src/components/Ellipsis/index.less deleted file mode 100644 index 3c0360c104..0000000000 --- a/src/components/Ellipsis/index.less +++ /dev/null @@ -1,24 +0,0 @@ -.ellipsis { - display: inline-block; - width: 100%; - overflow: hidden; - word-break: break-all; -} - -.lines { - position: relative; - .shadow { - position: absolute; - z-index: -999; - display: block; - color: transparent; - opacity: 0; - } -} - -.lineClamp { - position: relative; - display: -webkit-box; - overflow: hidden; - text-overflow: ellipsis; -} diff --git a/src/components/Ellipsis/index.test.js b/src/components/Ellipsis/index.test.js deleted file mode 100644 index 4d057b24e7..0000000000 --- a/src/components/Ellipsis/index.test.js +++ /dev/null @@ -1,13 +0,0 @@ -import { getStrFullLength, cutStrByFullLength } from './index'; - -describe('test calculateShowLength', () => { - it('get full length', () => { - expect(getStrFullLength('一二,a,')).toEqual(8); - }); - it('cut str by full length', () => { - expect(cutStrByFullLength('一二,a,', 7)).toEqual('一二,a'); - }); - it('cut str when length small', () => { - expect(cutStrByFullLength('一22三', 5)).toEqual('一22'); - }); -}); diff --git a/src/components/Ellipsis/index.zh-CN.md b/src/components/Ellipsis/index.zh-CN.md deleted file mode 100644 index 1875b17c20..0000000000 --- a/src/components/Ellipsis/index.zh-CN.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -title: Ellipsis -subtitle: 文本自动省略号 -cols: 1 -order: 10 ---- - -文本过长自动处理省略号,支持按照文本长度和最大行数两种方式截取。 - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| -------------------- | ------------------------------------------------ | ------- | ------ | -| tooltip | 移动到文本展示完整内容的提示 | boolean | - | -| length | 在按照长度截取下的文本最大字符数,超过则截取省略 | number | - | -| lines | 在按照行数截取下最大的行数,超过则截取省略 | number | `1` | -| fullWidthRecognition | 是否将全角字符的长度视为 2 来计算字符串长度 | boolean | - | diff --git a/src/components/Exception/demo/403.md b/src/components/Exception/demo/403.md deleted file mode 100644 index aa65a7135d..0000000000 --- a/src/components/Exception/demo/403.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -order: 2 -title: - zh-CN: 403 页面 - en-US: 403 Page ---- - -## zh-CN - -403 页面,配合自定义操作。 - -## en-US - -403 page with custom operations. - -```jsx -import Exception from 'ant-design-pro/lib/Exception'; -import { Button } from 'antd'; - -const actions = ( -
    - - -
    -); -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Exception/demo/404.md b/src/components/Exception/demo/404.md deleted file mode 100644 index 6510923cd7..0000000000 --- a/src/components/Exception/demo/404.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -order: 0 -title: - zh-CN: 404 页面 - en-US: 404 Page ---- - -## zh-CN - -404 页面。 - -## en-US - -404 page. - -```jsx -import Exception from 'ant-design-pro/lib/Exception'; - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Exception/demo/500.md b/src/components/Exception/demo/500.md deleted file mode 100644 index b017e7715c..0000000000 --- a/src/components/Exception/demo/500.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -order: 1 -title: - zh-CN: 500 页面 - en-US: 500 Page ---- - -## zh-CN - -500 页面。 - -## en-US - -500 page. - -```jsx -import Exception from 'ant-design-pro/lib/Exception'; - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/Exception/index.d.ts b/src/components/Exception/index.d.ts deleted file mode 100644 index b8cb65dd92..0000000000 --- a/src/components/Exception/index.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import * as H from 'history'; - -export interface ExceptionProps< - L = { - to: H.LocationDescriptor; - href?: H.LocationDescriptor; - replace?: boolean; - innerRef?: (node: HTMLAnchorElement | null) => void; - } -> { - type?: '403' | '404' | '500'; - title?: React.ReactNode; - desc?: React.ReactNode; - img?: string; - actions?: React.ReactNode; - linkElement?: string | React.ComponentType; - style?: React.CSSProperties; - className?: string; - backText?: React.ReactNode; - redirect?: string; -} -export default class Exception extends React.Component {} diff --git a/src/components/Exception/index.en-US.md b/src/components/Exception/index.en-US.md deleted file mode 100644 index 9e8f5166a0..0000000000 --- a/src/components/Exception/index.en-US.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Exception -cols: 1 -order: 5 ---- - -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. - -## API - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| backText | default return button text | ReactNode | back to home | -| 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'} | - | -| title | title | ReactNode | - | -| desc | supplementary description | ReactNode | - | -| img | the url of background image | string | - | -| actions | suggested operations, a default 'Home' link will show if not set | ReactNode | - | -| linkElement | to specify the element of link | string\|ReactElement | 'a' | -| redirect | redirect path | string | '/' | diff --git a/src/components/Exception/index.js b/src/components/Exception/index.js deleted file mode 100644 index 2c7223cc76..0000000000 --- a/src/components/Exception/index.js +++ /dev/null @@ -1,61 +0,0 @@ -import React, { createElement } from 'react'; -import classNames from 'classnames'; -import { Button } from 'antd'; -import config from './typeConfig'; -import styles from './index.less'; - -class Exception extends React.PureComponent { - static defaultProps = { - backText: 'back to home', - redirect: '/', - }; - - constructor(props) { - super(props); - this.state = {}; - } - - render() { - const { - className, - backText, - linkElement = 'a', - type, - title, - desc, - img, - actions, - redirect, - ...rest - } = this.props; - const pageType = type in config ? type : '404'; - const clsString = classNames(styles.exception, className); - return ( -
    -
    -
    -
    -
    -

    {title || config[pageType].title}

    -
    {desc || config[pageType].desc}
    -
    - {actions || - createElement( - linkElement, - { - to: redirect, - href: redirect, - }, - - )} -
    -
    -
    - ); - } -} - -export default Exception; diff --git a/src/components/Exception/index.less b/src/components/Exception/index.less deleted file mode 100644 index 5393bb7187..0000000000 --- a/src/components/Exception/index.less +++ /dev/null @@ -1,89 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.exception { - display: flex; - align-items: center; - height: 80%; - min-height: 500px; - - .imgBlock { - flex: 0 0 62.5%; - width: 62.5%; - padding-right: 152px; - zoom: 1; - &::before, - &::after { - display: table; - content: ' '; - } - &::after { - clear: both; - height: 0; - font-size: 0; - visibility: hidden; - } - } - - .imgEle { - float: right; - width: 100%; - max-width: 430px; - height: 360px; - background-repeat: no-repeat; - background-position: 50% 50%; - background-size: contain; - } - - .content { - flex: auto; - - h1 { - margin-bottom: 24px; - color: #434e59; - font-weight: 600; - font-size: 72px; - line-height: 72px; - } - - .desc { - margin-bottom: 16px; - color: @text-color-secondary; - font-size: 20px; - line-height: 28px; - } - - .actions { - button:not(:last-child) { - margin-right: 8px; - } - } - } -} - -@media screen and (max-width: @screen-xl) { - .exception { - .imgBlock { - padding-right: 88px; - } - } -} - -@media screen and (max-width: @screen-sm) { - .exception { - display: block; - text-align: center; - .imgBlock { - margin: 0 auto 24px; - padding-right: 0; - } - } -} - -@media screen and (max-width: @screen-xs) { - .exception { - .imgBlock { - margin-bottom: -24px; - overflow: hidden; - } - } -} diff --git a/src/components/Exception/index.zh-CN.md b/src/components/Exception/index.zh-CN.md deleted file mode 100644 index 0769e6d703..0000000000 --- a/src/components/Exception/index.zh-CN.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: Exception -subtitle: 异常 -cols: 1 -order: 5 ---- - -异常页用于对页面特定的异常状态进行反馈。通常,它包含对错误状态的阐述,并向用户提供建议或操作,避免用户感到迷失和困惑。 - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| backText | 默认的返回按钮文本 | ReactNode | back to home | -| type | 页面类型,若配置,则自带对应类型默认的 `title`,`desc`,`img`,此默认设置可以被 `title`,`desc`,`img` 覆盖 | Enum {'403', '404', '500'} | - | -| title | 标题 | ReactNode | - | -| desc | 补充描述 | ReactNode | - | -| img | 背景图片地址 | string | - | -| actions | 建议操作,配置此属性时默认的『返回首页』按钮不生效 | ReactNode | - | -| linkElement | 定义链接的元素 | string\|ReactElement | 'a' | -| redirect | 返回按钮的跳转地址 | string | '/' | diff --git a/src/components/Exception/typeConfig.js b/src/components/Exception/typeConfig.js deleted file mode 100644 index b6e1ee5a9b..0000000000 --- a/src/components/Exception/typeConfig.js +++ /dev/null @@ -1,19 +0,0 @@ -const config = { - 403: { - img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg', - title: '403', - desc: '抱歉,你无权访问该页面', - }, - 404: { - img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg', - title: '404', - desc: '抱歉,你访问的页面不存在', - }, - 500: { - img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg', - title: '500', - desc: '抱歉,服务器出错了', - }, -}; - -export default config; diff --git a/src/components/FooterToolbar/demo/basic.md b/src/components/FooterToolbar/demo/basic.md deleted file mode 100644 index 196f250e46..0000000000 --- a/src/components/FooterToolbar/demo/basic.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -order: 0 -title: - zh-CN: 演示 - en-US: demo -iframe: 400 ---- - -## zh-CN - -浮动固定页脚。 - -## en-US - -Fixed to the footer. - -```jsx -import FooterToolbar from 'ant-design-pro/lib/FooterToolbar'; -import { Button } from 'antd'; - -ReactDOM.render( -
    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    -

    Content Content Content Content

    - - - - -
    , - mountNode -); -``` diff --git a/src/components/FooterToolbar/index.d.ts b/src/components/FooterToolbar/index.d.ts deleted file mode 100644 index 9ec202c1c5..0000000000 --- a/src/components/FooterToolbar/index.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -export interface FooterToolbarProps { - extra: React.ReactNode; - style?: React.CSSProperties; - className?: string; -} - -export default class FooterToolbar extends React.Component {} diff --git a/src/components/FooterToolbar/index.en-US.md b/src/components/FooterToolbar/index.en-US.md deleted file mode 100644 index 9816189ffd..0000000000 --- a/src/components/FooterToolbar/index.en-US.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: FooterToolbar -cols: 1 -order: 6 ---- - -A toolbar fixed at the bottom. - -## Usage - -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. - -## API - -| Property | Description | Type | Default | -| -------- | ------------------------------------ | --------- | ------- | -| children | toolbar content, align to the right | ReactNode | - | -| extra | extra information, align to the left | ReactNode | - | diff --git a/src/components/FooterToolbar/index.js b/src/components/FooterToolbar/index.js deleted file mode 100644 index d43f72fb45..0000000000 --- a/src/components/FooterToolbar/index.js +++ /dev/null @@ -1,47 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import styles from './index.less'; - -export default class FooterToolbar extends Component { - static contextTypes = { - isMobile: PropTypes.bool, - }; - - state = { - width: undefined, - }; - - componentDidMount() { - window.addEventListener('resize', this.resizeFooterToolbar); - this.resizeFooterToolbar(); - } - - componentWillUnmount() { - window.removeEventListener('resize', this.resizeFooterToolbar); - } - - resizeFooterToolbar = () => { - const sider = document.querySelector('.ant-layout-sider'); - if (sider == null) { - return; - } - const { isMobile } = this.context; - const width = isMobile ? null : `calc(100% - ${sider.style.width})`; - const { width: stateWidth } = this.state; - if (stateWidth !== width) { - this.setState({ width }); - } - }; - - render() { - const { children, className, extra, ...restProps } = this.props; - const { width } = this.state; - return ( -
    -
    {extra}
    -
    {children}
    -
    - ); - } -} diff --git a/src/components/FooterToolbar/index.less b/src/components/FooterToolbar/index.less deleted file mode 100644 index 5073cff61b..0000000000 --- a/src/components/FooterToolbar/index.less +++ /dev/null @@ -1,33 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.toolbar { - position: fixed; - right: 0; - bottom: 0; - z-index: 9; - width: 100%; - height: 56px; - padding: 0 24px; - line-height: 56px; - background: #fff; - border-top: 1px solid @border-color-split; - box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03); - - &::after { - display: block; - clear: both; - content: ''; - } - - .left { - float: left; - } - - .right { - float: right; - } - - button + button { - margin-left: 8px; - } -} diff --git a/src/components/FooterToolbar/index.zh-CN.md b/src/components/FooterToolbar/index.zh-CN.md deleted file mode 100644 index ff52e1555e..0000000000 --- a/src/components/FooterToolbar/index.zh-CN.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: FooterToolbar -subtitle: 底部工具栏 -cols: 1 -order: 6 ---- - -固定在底部的工具栏。 - -## 何时使用 - -固定在内容区域的底部,不随滚动条移动,常用于长页面的数据搜集和提交工作。 - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| -------- | -------------------- | --------- | ------ | -| children | 工具栏内容,向右对齐 | ReactNode | - | -| extra | 额外信息,向左对齐 | ReactNode | - | diff --git a/src/components/GlobalFooter/demo/basic.md b/src/components/GlobalFooter/demo/basic.md deleted file mode 100644 index 798846ecb5..0000000000 --- a/src/components/GlobalFooter/demo/basic.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -order: 0 -title: 演示 -iframe: 400 ---- - -基本页脚。 - -```jsx -import GlobalFooter from 'ant-design-pro/lib/GlobalFooter'; -import { Icon } from 'antd'; - -const links = [ - { - key: '帮助', - title: '帮助', - href: '', - }, - { - key: 'github', - title: , - href: 'https://github.com/ant-design/ant-design-pro', - blankTarget: true, - }, - { - key: '条款', - title: '条款', - href: '', - blankTarget: true, - }, -]; - -const copyright = ( -
    - Copyright 2017 蚂蚁金服体验技术部出品 -
    -); - -ReactDOM.render( -
    -
    - -
    , - mountNode -); -``` diff --git a/src/components/GlobalFooter/index.d.ts b/src/components/GlobalFooter/index.d.ts deleted file mode 100644 index efde77dbd4..0000000000 --- a/src/components/GlobalFooter/index.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -export interface GlobalFooterProps { - links?: Array<{ - key?: string; - title: React.ReactNode; - href: string; - blankTarget?: boolean; - }>; - copyright?: React.ReactNode; - style?: React.CSSProperties; - className?: string; -} - -export default class GlobalFooter extends React.Component {} diff --git a/src/components/GlobalFooter/index.md b/src/components/GlobalFooter/index.md deleted file mode 100644 index 5d6058f693..0000000000 --- a/src/components/GlobalFooter/index.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: GlobalFooter -subtitle: 全局页脚 -cols: 1 -order: 7 ---- - -页脚属于全局导航的一部分,作为对顶部导航的补充,通过传递数据控制展示内容。 - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| --------- | -------- | ---------------------------------------------------------------- | ------ | -| links | 链接数据 | array<{ title: ReactNode, href: string, blankTarget?: boolean }> | - | -| copyright | 版权信息 | ReactNode | - | diff --git a/src/components/GlobalFooter/index.js b/src/components/GlobalFooter/index.tsx similarity index 67% rename from src/components/GlobalFooter/index.js rename to src/components/GlobalFooter/index.tsx index 1c2fb74efe..01166243a7 100644 --- a/src/components/GlobalFooter/index.js +++ b/src/components/GlobalFooter/index.tsx @@ -2,7 +2,19 @@ import React from 'react'; import classNames from 'classnames'; import styles from './index.less'; -const GlobalFooter = ({ className, links, copyright }) => { +export interface GlobalFooterProps { + links?: Array<{ + key?: string; + title: React.ReactNode; + href: string; + blankTarget?: boolean; + }>; + copyright?: React.ReactNode; + style?: React.CSSProperties; + className?: string; +} + +const GlobalFooter: React.SFC = ({ className, links, copyright }) => { const clsString = classNames(styles.globalFooter, className); return (
    diff --git a/src/components/GlobalHeader/AvatarDropdown.tsx b/src/components/GlobalHeader/AvatarDropdown.tsx new file mode 100644 index 0000000000..5b135c6c34 --- /dev/null +++ b/src/components/GlobalHeader/AvatarDropdown.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { Avatar, Menu, Spin, Icon } from 'antd'; +import { FormattedMessage } from 'umi-plugin-react/locale'; +import { ClickParam } from 'antd/lib/menu'; +import { ConnectProps, ConnectState } from '@/models/connect'; +import { CurrentUser } from '@/models/user'; +import { connect } from 'dva'; +import router from 'umi/router'; +import HeaderDropdown from '../HeaderDropdown'; +import styles from './index.less'; + +export interface GlobalHeaderRightProps extends ConnectProps { + currentUser?: CurrentUser; + menu?: boolean; +} + +class AvatarDropdown extends React.Component { + onMenuClick = (event: ClickParam) => { + const { key } = event; + + if (key === 'logout') { + const { dispatch } = this.props; + if (dispatch) { + dispatch({ + type: 'login/logout', + }); + } + + return; + } + router.push(`/account/${key}`); + }; + render() { + const { currentUser = {}, menu } = this.props; + if (!menu) { + return ( + + + {currentUser.name} + + ); + } + const menuHeaderDropdown = ( + + + + + + + + + + + + + + + + ); + + return currentUser && currentUser.name ? ( + + + + {currentUser.name} + + + ) : ( + + ); + } +} +export default connect(({ user }: ConnectState) => ({ + currentUser: user.currentUser, +}))(AvatarDropdown); diff --git a/src/components/GlobalHeader/NoticeIconView.tsx b/src/components/GlobalHeader/NoticeIconView.tsx new file mode 100644 index 0000000000..d79550b028 --- /dev/null +++ b/src/components/GlobalHeader/NoticeIconView.tsx @@ -0,0 +1,149 @@ +import { ConnectProps, ConnectState } from '@/models/connect'; +import { NoticeItem } from '@/models/global'; +import { CurrentUser } from '@/models/user'; +import React, { Component } from 'react'; +import { Tag, message } from 'antd'; +import { formatMessage } from 'umi-plugin-react/locale'; +import moment from 'moment'; +import groupBy from 'lodash/groupBy'; +import NoticeIcon from '../NoticeIcon'; +import styles from './index.less'; +import { connect } from 'dva'; + +export interface GlobalHeaderRightProps extends ConnectProps { + notices?: NoticeItem[]; + currentUser?: CurrentUser; + fetchingNotices?: boolean; + onNoticeVisibleChange?: (visible: boolean) => void; + onNoticeClear?: (tabName?: string) => void; +} + +class GlobalHeaderRight extends Component { + getNoticeData = (): { [key: string]: NoticeItem[] } => { + const { notices = [] } = this.props; + if (notices.length === 0) { + return {}; + } + const newNotices = notices.map(notice => { + const newNotice = { ...notice }; + if (newNotice.datetime) { + newNotice.datetime = moment(notice.datetime as string).fromNow(); + } + if (newNotice.id) { + newNotice.key = newNotice.id; + } + if (newNotice.extra && newNotice.status) { + const color = { + todo: '', + processing: 'blue', + urgent: 'red', + doing: 'gold', + }[newNotice.status]; + newNotice.extra = ( + + {newNotice.extra} + + ); + } + return newNotice; + }); + return groupBy(newNotices, 'type'); + }; + + getUnreadData = (noticeData: { [key: string]: NoticeItem[] }) => { + const unreadMsg: { [key: string]: number } = {}; + Object.entries(noticeData).forEach(([key, value]) => { + if (!unreadMsg[key]) { + unreadMsg[key] = 0; + } + if (Array.isArray(value)) { + unreadMsg[key] = value.filter(item => !item.read).length; + } + }); + return unreadMsg; + }; + + changeReadState = (clickedItem: NoticeItem) => { + const { id } = clickedItem; + const { dispatch } = this.props; + if (dispatch) { + dispatch({ + type: 'global/changeNoticeReadState', + payload: id, + }); + } + }; + componentDidMount() { + const { dispatch } = this.props; + if (dispatch) { + dispatch({ + type: 'global/fetchNotices', + }); + } + } + handleNoticeClear = (title: string, key: string) => { + const { dispatch } = this.props; + message.success(`${formatMessage({ id: 'component.noticeIcon.cleared' })} ${title}`); + if (dispatch) { + dispatch({ + type: 'global/clearNotices', + payload: key, + }); + } + }; + render() { + const { currentUser, fetchingNotices, onNoticeVisibleChange } = this.props; + const noticeData = this.getNoticeData(); + const unreadMsg = this.getUnreadData(noticeData); + + return ( + { + this.changeReadState(item as NoticeItem); + }} + loading={fetchingNotices} + clearText={formatMessage({ id: 'component.noticeIcon.clear' })} + viewMoreText={formatMessage({ id: 'component.noticeIcon.view-more' })} + onClear={this.handleNoticeClear} + onPopupVisibleChange={onNoticeVisibleChange} + onViewMore={() => message.info('Click on view more')} + clearClose + > + + + + + ); + } +} + +export default connect(({ user, global, loading }: ConnectState) => ({ + currentUser: user.currentUser, + collapsed: global.collapsed, + fetchingMoreNotices: loading.effects['global/fetchMoreNotices'], + fetchingNotices: loading.effects['global/fetchNotices'], + notices: global.notices, +}))(GlobalHeaderRight); diff --git a/src/components/GlobalHeader/RightContent.d.ts b/src/components/GlobalHeader/RightContent.d.ts deleted file mode 100644 index 275d9996a0..0000000000 --- a/src/components/GlobalHeader/RightContent.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import { DropDownProps } from 'antd/lib/dropdown'; -import { ClickParam } from 'antd/es/menu'; -import { SiderTheme } from 'antd/es/Layout/Sider'; - -export interface GlobalHeaderRightProps { - notices?: any[]; - dispatch?: (args: any) => void; - currentUser?: { - avatar?: string; - name?: string; - title?: string; - group?: string; - signature?: string; - geographic?: any; - tags?: any[]; - unreadCount: number; - }; - fetchingNotices?: boolean; - onNoticeVisibleChange?: (visible: boolean) => void; - onMenuClick?: (param: ClickParam) => void; - onNoticeClear?: (tabName: string) => void; - theme?: SiderTheme; -} - -export default class GlobalHeaderRight extends React.Component {} diff --git a/src/components/GlobalHeader/RightContent.js b/src/components/GlobalHeader/RightContent.js deleted file mode 100644 index d40e1166c6..0000000000 --- a/src/components/GlobalHeader/RightContent.js +++ /dev/null @@ -1,194 +0,0 @@ -import React, { PureComponent } from 'react'; -import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale'; -import { Spin, Tag, Menu, Icon, Avatar, Tooltip, message } from 'antd'; -import moment from 'moment'; -import groupBy from 'lodash/groupBy'; -import NoticeIcon from '../NoticeIcon'; -import HeaderSearch from '../HeaderSearch'; -import HeaderDropdown from '../HeaderDropdown'; -import SelectLang from '../SelectLang'; -import styles from './index.less'; - -export default class GlobalHeaderRight extends PureComponent { - getNoticeData() { - const { notices = [] } = this.props; - if (notices.length === 0) { - return {}; - } - const newNotices = notices.map(notice => { - const newNotice = { ...notice }; - if (newNotice.datetime) { - newNotice.datetime = moment(notice.datetime).fromNow(); - } - if (newNotice.id) { - newNotice.key = newNotice.id; - } - if (newNotice.extra && newNotice.status) { - const color = { - todo: '', - processing: 'blue', - urgent: 'red', - doing: 'gold', - }[newNotice.status]; - newNotice.extra = ( - - {newNotice.extra} - - ); - } - return newNotice; - }); - return groupBy(newNotices, 'type'); - } - - getUnreadData = noticeData => { - const unreadMsg = {}; - Object.entries(noticeData).forEach(([key, value]) => { - if (!unreadMsg[key]) { - unreadMsg[key] = 0; - } - if (Array.isArray(value)) { - unreadMsg[key] = value.filter(item => !item.read).length; - } - }); - return unreadMsg; - }; - - changeReadState = clickedItem => { - const { id } = clickedItem; - const { dispatch } = this.props; - dispatch({ - type: 'global/changeNoticeReadState', - payload: id, - }); - }; - - render() { - const { - currentUser, - fetchingNotices, - onNoticeVisibleChange, - onMenuClick, - onNoticeClear, - theme, - } = this.props; - const menu = ( - - - - - - - - - - - - - - - - - - - - ); - const noticeData = this.getNoticeData(); - const unreadMsg = this.getUnreadData(noticeData); - let className = styles.right; - if (theme === 'dark') { - className = `${styles.right} ${styles.dark}`; - } - return ( -
    - { - console.log('input', value); // eslint-disable-line - }} - onPressEnter={value => { - console.log('enter', value); // eslint-disable-line - }} - /> - - - - - - { - console.log(item, tabProps); // eslint-disable-line - this.changeReadState(item, tabProps); - }} - loading={fetchingNotices} - locale={{ - emptyText: formatMessage({ id: 'component.noticeIcon.empty' }), - clear: formatMessage({ id: 'component.noticeIcon.clear' }), - viewMore: formatMessage({ id: 'component.noticeIcon.view-more' }), - notification: formatMessage({ id: 'component.globalHeader.notification' }), - message: formatMessage({ id: 'component.globalHeader.message' }), - event: formatMessage({ id: 'component.globalHeader.event' }), - }} - onClear={onNoticeClear} - onPopupVisibleChange={onNoticeVisibleChange} - onViewMore={() => message.info('Click on view more')} - clearClose - > - - - - - {currentUser.name ? ( - - - - {currentUser.name} - - - ) : ( - - )} - -
    - ); - } -} diff --git a/src/components/GlobalHeader/RightContent.tsx b/src/components/GlobalHeader/RightContent.tsx new file mode 100644 index 0000000000..cf4f5bf6e5 --- /dev/null +++ b/src/components/GlobalHeader/RightContent.tsx @@ -0,0 +1,75 @@ +import { ConnectProps, ConnectState } from '@/models/connect'; +import React, { Component } from 'react'; +import { Icon, Tooltip } from 'antd'; +import { formatMessage } from 'umi-plugin-react/locale'; +import HeaderSearch from '../HeaderSearch'; +import SelectLang from '../SelectLang'; +import styles from './index.less'; +import Avatar from './AvatarDropdown'; +import { connect } from 'dva'; + +export type SiderTheme = 'light' | 'dark'; +export interface GlobalHeaderRightProps extends ConnectProps { + theme?: SiderTheme; + layout: 'sidemenu' | 'topmenu'; +} + +class GlobalHeaderRight extends Component { + render() { + const { theme, layout } = this.props; + let className = styles.right; + + if (theme === 'dark' && layout === 'topmenu') { + className = `${styles.right} ${styles.dark}`; + } + + return ( +
    + { + console.log('input', value); // tslint:disable-line no-console + }} + onPressEnter={value => { + console.log('enter', value); // tslint:disable-line no-console + }} + /> + + + + + + + +
    + ); + } +} + +export default connect(({ settings }: ConnectState) => ({ + theme: settings.navTheme, + layout: settings.layout, +}))(GlobalHeaderRight); diff --git a/src/components/GlobalHeader/index.d.ts b/src/components/GlobalHeader/index.d.ts deleted file mode 100644 index 7d2fcf6e3c..0000000000 --- a/src/components/GlobalHeader/index.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; - -export interface GlobalHeaderProps { - collapsed?: boolean; - onCollapse?: (collapsed: boolean) => void; - isMobile?: boolean; - logo?: string; - onNoticeClear?: (type: string) => void; - onMenuClick?: ({ key: string }) => void; - onNoticeVisibleChange?: (b: boolean) => void; -} - -export default class GlobalHeader extends React.Component {} diff --git a/src/components/GlobalHeader/index.js b/src/components/GlobalHeader/index.js deleted file mode 100644 index fe96cdea6d..0000000000 --- a/src/components/GlobalHeader/index.js +++ /dev/null @@ -1,41 +0,0 @@ -import React, { PureComponent } from 'react'; -import { Icon } from 'antd'; -import Link from 'umi/link'; -import Debounce from 'lodash-decorators/debounce'; -import styles from './index.less'; -import RightContent from './RightContent'; - -export default class GlobalHeader extends PureComponent { - componentWillUnmount() { - this.triggerResizeEvent.cancel(); - } - /* eslint-disable*/ - @Debounce(600) - triggerResizeEvent() { - // eslint-disable-line - const event = document.createEvent('HTMLEvents'); - event.initEvent('resize', true, false); - window.dispatchEvent(event); - } - toggle = () => { - const { collapsed, onCollapse } = this.props; - onCollapse(!collapsed); - this.triggerResizeEvent(); - }; - render() { - const { collapsed, isMobile, logo } = this.props; - return ( -
    - {isMobile && ( - - logo - - )} - - - - -
    - ); - } -} diff --git a/src/components/GlobalHeader/index.less b/src/components/GlobalHeader/index.less index e66510b90f..75b450bfce 100644 --- a/src/components/GlobalHeader/index.less +++ b/src/components/GlobalHeader/index.less @@ -2,14 +2,6 @@ @pro-header-hover-bg: rgba(0, 0, 0, 0.025); -.header { - position: relative; - height: @layout-header-height; - padding: 0; - background: #fff; - box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); -} - .logo { display: inline-block; height: @layout-header-height; @@ -100,30 +92,28 @@ } @media only screen and (max-width: @screen-md) { - .header { - :global(.ant-divider-vertical) { - vertical-align: unset; - } - .name { - display: none; - } - i.trigger { - padding: 22px 12px; - } - .logo { - position: relative; - padding-right: 12px; - padding-left: 12px; - } - .right { - position: absolute; - top: 0; - right: 12px; - background: #fff; - .account { - .avatar { - margin-right: 0; - } + :global(.ant-divider-vertical) { + vertical-align: unset; + } + .name { + display: none; + } + i.trigger { + padding: 22px 12px; + } + .logo { + position: relative; + padding-right: 12px; + padding-left: 12px; + } + .right { + position: absolute; + top: 0; + right: 12px; + background: #fff; + .account { + .avatar { + margin-right: 0; } } } diff --git a/src/components/HeaderDropdown/index.d.ts b/src/components/HeaderDropdown/index.d.ts deleted file mode 100644 index a1fd50aa0f..0000000000 --- a/src/components/HeaderDropdown/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import { DropDownProps } from 'antd/lib/dropdown'; - -declare type OverlayFunc = () => React.ReactNode; - -export interface HeaderDropdownProps extends DropDownProps { - overlayClassName?: string; - overlay: React.ReactNode | OverlayFunc; - placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter'; -} - -export default class HeaderDropdown extends React.Component {} diff --git a/src/components/HeaderDropdown/index.js b/src/components/HeaderDropdown/index.js deleted file mode 100644 index a19c471ac1..0000000000 --- a/src/components/HeaderDropdown/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import React, { PureComponent } from 'react'; -import { Dropdown } from 'antd'; -import classNames from 'classnames'; -import styles from './index.less'; - -export default class HeaderDropdown extends PureComponent { - render() { - const { overlayClassName, ...props } = this.props; - return ( - - ); - } -} diff --git a/src/components/HeaderDropdown/index.tsx b/src/components/HeaderDropdown/index.tsx new file mode 100644 index 0000000000..897c8199e8 --- /dev/null +++ b/src/components/HeaderDropdown/index.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Dropdown } from 'antd'; +import { DropDownProps } from 'antd/es/dropdown'; +import classNames from 'classnames'; +import styles from './index.less'; + +declare type OverlayFunc = () => React.ReactNode; + +export interface HeaderDropdownProps extends DropDownProps { + overlayClassName?: string; + overlay: React.ReactNode | OverlayFunc; + placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter'; +} + +const HeaderDropdown: React.FC = ({ overlayClassName: cls, ...restProps }) => ( + +); + +export default HeaderDropdown; diff --git a/src/components/HeaderSearch/demo/basic.md b/src/components/HeaderSearch/demo/basic.md deleted file mode 100644 index ec9699882a..0000000000 --- a/src/components/HeaderSearch/demo/basic.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -order: 0 -title: 全局搜索 ---- - -通常放置在导航工具条右侧。(点击搜索图标预览效果) - -```jsx -import HeaderSearch from 'ant-design-pro/lib/HeaderSearch'; - -ReactDOM.render( -
    - { - console.log('input', value); // eslint-disable-line - }} - onPressEnter={value => { - console.log('enter', value); // eslint-disable-line - }} - /> -
    , - mountNode -); -``` diff --git a/src/components/HeaderSearch/index.d.ts b/src/components/HeaderSearch/index.d.ts deleted file mode 100644 index fcf7c11d22..0000000000 --- a/src/components/HeaderSearch/index.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -export interface HeaderSearchProps { - placeholder?: string; - dataSource?: string[]; - defaultOpen?: boolean; - open?: boolean; - onSearch?: (value: string) => void; - onChange?: (value: string) => void; - onVisibleChange?: (visible: boolean) => void; - onPressEnter?: (value: string) => void; - style?: React.CSSProperties; - className?: string; -} - -export default class HeaderSearch extends React.Component {} diff --git a/src/components/HeaderSearch/index.en-US.md b/src/components/HeaderSearch/index.en-US.md deleted file mode 100644 index c9906e7650..0000000000 --- a/src/components/HeaderSearch/index.en-US.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: HeaderSearch -subtitle: -cols: 1 -order: 8 ---- - -Usually placed as an entry to the global search, placed on the right side of the navigation toolbar. - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| placeholder | placeholder text | string | - | -| dataSource | current list of prompts | string[] | - | -| onSearch | Called when searching items. | function(value) | - | -| onChange | Called when select an option or input value change, or value of input is changed | function(value) | - | -| onSelect | Called when a option is selected. param is option's value and option instance. | function(value) | - | -| onPressEnter | Callback when pressing Enter | function(value) | - | -| onVisibleChange | Show or hide the callback of the text box | function(value) | - | -| defaultOpen | The input box is displayed for the first time. | boolean | false | -| open | The input box is displayed | boolean | false | diff --git a/src/components/HeaderSearch/index.js b/src/components/HeaderSearch/index.tsx similarity index 67% rename from src/components/HeaderSearch/index.js rename to src/components/HeaderSearch/index.tsx index 04f8b38ec8..dc252603c3 100644 --- a/src/components/HeaderSearch/index.js +++ b/src/components/HeaderSearch/index.tsx @@ -1,24 +1,29 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; +import React, { Component } from 'react'; import { Input, Icon, AutoComplete } from 'antd'; +import { DataSourceItemType } from 'antd/es/auto-complete'; import classNames from 'classnames'; -import Debounce from 'lodash-decorators/debounce'; -import Bind from 'lodash-decorators/bind'; +import debounce from 'lodash/debounce'; import styles from './index.less'; -export default class HeaderSearch extends PureComponent { - static propTypes = { - className: PropTypes.string, - placeholder: PropTypes.string, - onSearch: PropTypes.func, - onChange: PropTypes.func, - onPressEnter: PropTypes.func, - defaultActiveFirstOption: PropTypes.bool, - dataSource: PropTypes.array, - defaultOpen: PropTypes.bool, - onVisibleChange: PropTypes.func, - }; +export interface HeaderSearchProps { + onPressEnter: (value: string) => void; + onSearch: (value: string) => void; + onChange: (value: string) => void; + onVisibleChange: (b: boolean) => void; + className: string; + placeholder: string; + defaultActiveFirstOption: boolean; + dataSource: DataSourceItemType[]; + defaultOpen: boolean; + open?: boolean; +} + +interface HeaderSearchState { + value: string; + searchMode: boolean; +} +export default class HeaderSearch extends Component { static defaultProps = { defaultActiveFirstOption: false, onPressEnter: () => {}, @@ -31,7 +36,7 @@ export default class HeaderSearch extends PureComponent { onVisibleChange: () => {}, }; - static getDerivedStateFromProps(props) { + static getDerivedStateFromProps(props: HeaderSearchProps) { if ('open' in props) { return { searchMode: props.open, @@ -40,19 +45,26 @@ export default class HeaderSearch extends PureComponent { return null; } - constructor(props) { + private timeout: NodeJS.Timeout = null!; + private inputRef: Input | null = null; + + constructor(props: HeaderSearchProps) { super(props); this.state = { searchMode: props.defaultOpen, value: '', }; + this.debouncePressEnter = debounce(this.debouncePressEnter, 500, { + leading: true, + trailing: false, + }); } componentWillUnmount() { clearTimeout(this.timeout); } - onKeyDown = e => { + onKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { const { onPressEnter } = this.props; const { value } = this.state; @@ -62,7 +74,7 @@ export default class HeaderSearch extends PureComponent { } }; - onChange = value => { + onChange = (value: string) => { const { onSearch, onChange } = this.props; this.setState({ value }); if (onSearch) { @@ -78,8 +90,8 @@ export default class HeaderSearch extends PureComponent { onVisibleChange(true); this.setState({ searchMode: true }, () => { const { searchMode } = this.state; - if (searchMode) { - this.input.focus(); + if (searchMode && this.inputRef) { + this.inputRef.focus(); } }); }; @@ -91,17 +103,11 @@ export default class HeaderSearch extends PureComponent { }); }; - // NOTE: 不能小于500,如果长按某键,第一次触发auto repeat的间隔是500ms,小于500会导致触发2次 - @Bind() - @Debounce(500, { - leading: true, - trailing: false, - }) - debouncePressEnter() { + debouncePressEnter = () => { const { onPressEnter } = this.props; const { value } = this.state; onPressEnter(value); - } + }; render() { const { className, placeholder, open, ...restProps } = this.props; @@ -127,11 +133,11 @@ export default class HeaderSearch extends PureComponent { {...restProps} className={inputClass} value={value} - onChange={this.onChange} + onChange={this.onChange as any} > { - this.input = node; + this.inputRef = node; }} aria-label={placeholder} placeholder={placeholder} diff --git a/src/components/HeaderSearch/index.zh-CN.md b/src/components/HeaderSearch/index.zh-CN.md deleted file mode 100644 index 8561eee8fe..0000000000 --- a/src/components/HeaderSearch/index.zh-CN.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: HeaderSearch -subtitle: 顶部搜索框 -cols: 1 -order: 8 ---- - -通常作为全局搜索的入口,放置在导航工具条右侧。 - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| --------------- | ------------------------------------------------- | --------------- | ------ | -| placeholder | 占位文字 | string | - | -| dataSource | 当前提示内容列表 | string[] | - | -| onSearch | 搜索补全项的时候调用 | function(value) | - | -| onChange | 选中 option,或 input 的 value 变化时,调用此函数 | function(value) | - | -| onSelect | 被选中时调用,参数为选中项的 value 值 | function(value) | - | -| onPressEnter | 按下回车时的回调 | function(value) | - | -| onVisibleChange | 显示或隐藏文本框的回调 | function(value) | - | -| defaultOpen | 输入框首次显示是否显示 | boolean | false | -| open | 控制输入框是否显示 | boolean | false | diff --git a/src/components/IconFont/index.js b/src/components/IconFont/index.js deleted file mode 100644 index 0b99dec3a7..0000000000 --- a/src/components/IconFont/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import { Icon } from 'antd'; -import { iconfontUrl as scriptUrl } from '../../defaultSettings'; - -// 使用: -// import IconFont from '@/components/IconFont'; -// -export default Icon.createFromIconfontCN({ scriptUrl }); diff --git a/src/components/Login/LoginItem.d.ts b/src/components/Login/LoginItem.d.ts deleted file mode 100644 index 563e94e048..0000000000 --- a/src/components/Login/LoginItem.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import { WrappedFormUtils } from 'antd/es/form/Form'; -import ItemMap from './map'; -import { Omit } from 'antd/es/_util/type'; - -export type WrappedLoginItemProps = Omit; -export type LoginItemType = { [K in keyof typeof ItemMap]: React.FC }; - -export interface LoginItemProps { - name?: string; - rules?: any[]; - style?: React.CSSProperties; - onGetCaptcha?: (event?: MouseEvent) => void; - placeholder?: string; - buttonText?: React.ReactNode; - onPressEnter?: (e: any) => void; - countDown?: number; - getCaptchaButtonText?: string; - getCaptchaSecondText?: string; - updateActive: (activeItem: any) => void; - form: WrappedFormUtils; - type: string; - defaultValue?: string; - customprops?: any; - onChange?: (e: any) => void; -} - -export default class LoginItem extends React.Component {} diff --git a/src/components/Login/LoginItem.js b/src/components/Login/LoginItem.js deleted file mode 100644 index b3cc4d48a9..0000000000 --- a/src/components/Login/LoginItem.js +++ /dev/null @@ -1,147 +0,0 @@ -import React, { Component } from 'react'; -import { Form, Input, Button, Row, Col } from 'antd'; -import omit from 'omit.js'; -import styles from './index.less'; -import ItemMap from './map'; -import LoginContext from './loginContext'; - -const FormItem = Form.Item; - -class WrapFormItem extends Component { - static defaultProps = { - getCaptchaButtonText: 'captcha', - getCaptchaSecondText: 'second', - }; - - constructor(props) { - super(props); - this.state = { - count: 0, - }; - } - - componentDidMount() { - const { updateActive, name } = this.props; - if (updateActive) { - updateActive(name); - } - } - - componentWillUnmount() { - clearInterval(this.interval); - } - - onGetCaptcha = () => { - const { onGetCaptcha } = this.props; - const result = onGetCaptcha ? onGetCaptcha() : null; - if (result === false) { - return; - } - if (result instanceof Promise) { - result.then(this.runGetCaptchaCountDown); - } else { - this.runGetCaptchaCountDown(); - } - }; - - getFormItemOptions = ({ onChange, defaultValue, customprops, rules }) => { - const options = { - rules: rules || customprops.rules, - }; - if (onChange) { - options.onChange = onChange; - } - if (defaultValue) { - options.initialValue = defaultValue; - } - return options; - }; - - runGetCaptchaCountDown = () => { - const { countDown } = this.props; - let count = countDown || 59; - this.setState({ count }); - this.interval = setInterval(() => { - count -= 1; - this.setState({ count }); - if (count === 0) { - clearInterval(this.interval); - } - }, 1000); - }; - - render() { - const { count } = this.state; - - const { - form: { getFieldDecorator }, - } = this.props; - - // 这么写是为了防止restProps中 带入 onChange, defaultValue, rules props - const { - onChange, - customprops, - defaultValue, - rules, - name, - getCaptchaButtonText, - getCaptchaSecondText, - updateActive, - type, - ...restProps - } = this.props; - - // get getFieldDecorator props - const options = this.getFormItemOptions(this.props); - - const otherProps = restProps || {}; - if (type === 'Captcha') { - const inputProps = omit(otherProps, ['onGetCaptcha', 'countDown']); - return ( - - - - {getFieldDecorator(name, options)()} - - - - - - - ); - } - return ( - - {getFieldDecorator(name, options)()} - - ); - } -} - -const LoginItem = {}; -Object.keys(ItemMap).forEach(key => { - const item = ItemMap[key]; - LoginItem[key] = props => ( - - {context => ( - - )} - - ); -}); - -export default LoginItem; diff --git a/src/components/Login/LoginSubmit.js b/src/components/Login/LoginSubmit.js deleted file mode 100644 index 4aebabf89a..0000000000 --- a/src/components/Login/LoginSubmit.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import classNames from 'classnames'; -import { Button, Form } from 'antd'; -import styles from './index.less'; - -const FormItem = Form.Item; - -const LoginSubmit = ({ className, ...rest }) => { - const clsString = classNames(styles.submit, className); - return ( - -
    ); -} +}; + +export default NoticeList; diff --git a/src/components/NoticeIcon/demo/basic.md b/src/components/NoticeIcon/demo/basic.md deleted file mode 100644 index 45037288f8..0000000000 --- a/src/components/NoticeIcon/demo/basic.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -order: 1 -title: 通知图标 ---- - -通常用在导航工具栏上。 - -```jsx -import NoticeIcon from 'ant-design-pro/lib/NoticeIcon'; - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/NoticeIcon/demo/popover.md b/src/components/NoticeIcon/demo/popover.md deleted file mode 100644 index 5aae3704ea..0000000000 --- a/src/components/NoticeIcon/demo/popover.md +++ /dev/null @@ -1,188 +0,0 @@ ---- -order: 2 -title: 带浮层卡片 ---- - -点击展开通知卡片,展现多种类型的通知,通常放在导航工具栏。 - -```jsx -import NoticeIcon from 'ant-design-pro/lib/NoticeIcon'; -import { Tag } from 'antd'; - -const data = [ - { - id: '000000001', - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', - title: '你收到了 14 份新周报', - datetime: '2017-08-09', - type: 'notification', - }, - { - id: '000000002', - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png', - title: '你推荐的 曲妮妮 已通过第三轮面试', - datetime: '2017-08-08', - type: 'notification', - }, - { - id: '000000003', - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png', - title: '这种模板可以区分多种通知类型', - datetime: '2017-08-07', - read: true, - type: 'notification', - }, - { - id: '000000004', - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', - title: '左侧图标用于区分不同的类型', - datetime: '2017-08-07', - type: 'notification', - }, - { - id: '000000005', - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', - title: '内容不要超过两行字,超出时自动截断', - datetime: '2017-08-07', - type: 'notification', - }, - { - id: '000000006', - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', - title: '曲丽丽 评论了你', - description: '描述信息描述信息描述信息', - datetime: '2017-08-07', - type: 'message', - clickClose: true, - }, - { - id: '000000007', - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', - title: '朱偏右 回复了你', - description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', - datetime: '2017-08-07', - type: 'message', - clickClose: true, - }, - { - id: '000000008', - avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', - title: '标题', - description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', - datetime: '2017-08-07', - type: 'message', - clickClose: true, - }, - { - id: '000000009', - title: '任务名称', - description: '任务需要在 2017-01-12 20:00 前启动', - extra: '未开始', - status: 'todo', - type: 'event', - }, - { - id: '000000010', - title: '第三方紧急代码变更', - description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', - extra: '马上到期', - status: 'urgent', - type: 'event', - }, - { - id: '000000011', - title: '信息安全考试', - description: '指派竹尔于 2017-01-09 前完成更新并发布', - extra: '已耗时 8 天', - status: 'doing', - type: 'event', - }, - { - id: '000000012', - title: 'ABCD 版本发布', - description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', - extra: '进行中', - status: 'processing', - type: 'event', - }, -]; - -function onItemClick(item, tabProps) { - console.log(item, tabProps); -} - -function onClear(tabTitle) { - console.log(tabTitle); -} - -function getNoticeData(notices) { - if (notices.length === 0) { - return {}; - } - const newNotices = notices.map(notice => { - const newNotice = { ...notice }; - // transform id to item key - if (newNotice.id) { - newNotice.key = newNotice.id; - } - if (newNotice.extra && newNotice.status) { - const color = { - todo: '', - processing: 'blue', - urgent: 'red', - doing: 'gold', - }[newNotice.status]; - newNotice.extra = ( - - {newNotice.extra} - - ); - } - return newNotice; - }); - return newNotices.reduce((pre, data) => { - if (!pre[data.type]) { - pre[data.type] = []; - } - pre[data.type].push(data); - return pre; - }, {}); -} - -const noticeData = getNoticeData(data); -const Demo = () => ( -
    - - - - - -
    -); - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/NoticeIcon/index.d.ts b/src/components/NoticeIcon/index.d.ts deleted file mode 100644 index 18b3c43327..0000000000 --- a/src/components/NoticeIcon/index.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import NoticeIconTab, { NoticeIconData } from './NoticeIconTab'; - -export interface NoticeIconProps { - count?: number; - bell?: React.ReactNode; - className?: string; - loading?: boolean; - onClear?: (tabName: string) => void; - onItemClick?: (item: NoticeIconData, tabProps: NoticeIconProps) => void; - onViewMore?: (tabProps: NoticeIconProps, e: MouseEvent) => void; - onTabChange?: (tabTile: string) => void; - style?: React.CSSProperties; - onPopupVisibleChange?: (visible: boolean) => void; - popupVisible?: boolean; - locale?: { - emptyText: string; - clear: string; - viewMore: string; - [key: string]: string; - }; - clearClose?: boolean; -} - -export default class NoticeIcon extends React.Component { - public static Tab: typeof NoticeIconTab; -} diff --git a/src/components/NoticeIcon/index.en-US.md b/src/components/NoticeIcon/index.en-US.md deleted file mode 100644 index a2e4dfcb3f..0000000000 --- a/src/components/NoticeIcon/index.en-US.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: NoticeIcon -subtitle: -cols: 1 -order: 9 ---- - -Used in navigation toolbar as a unified notification center for the entire product. - -## API - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| count | Total number of messages | number | - | -| bell | Change the bell Icon | ReactNode | `` | -| loading | Popup card loading status | boolean | `false` | -| onClear | Click to clear button the callback | function(tabName) | - | -| onItemClick | Click on the list item's callback | function(item, tabProps) | - | -| onPopupVisibleChange | Popup Card Showing or Hiding Callbacks | function(visible) | - | -| onTabChange | Switching callbacks for tabs | function(tabTitle) | - | -| onViewMore | Callback of click for view more | function(tabProps, event) | - | -| popupVisible | Popup card display state | boolean | - | -| locale | Default message text | Object | `{ emptyText: 'No notifications', clear: 'Clear', viewMore: 'Loading more' }` | -| clearClose | Close menu after clear | boolean | `false` | - -### NoticeIcon.Tab - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| count | Unread messages count of this tab | number | list.length | -| emptyText | Message text when list is empty | ReactNode | - | -| emptyImage | Image when list is empty | string | - | -| list | List data, format refer to the following table | Array | `[]` | -| showClear | Clear button display status | boolean | `true` | -| showViewMore | View more button display status | boolean | `false` | -| title | header for message Tab, the actual text is `locale[title] || title` | string | - | - -### Tab data - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| avatar | avatar img url | string \| ReactNode | - | -| title | title | ReactNode | - | -| description | description info | ReactNode | - | -| datetime | Timestamps | ReactNode | - | -| extra | Additional information in the upper right corner of the list item | ReactNode | - | -| clickClose | Close menu after clicking list item | boolean | `false` | diff --git a/src/components/NoticeIcon/index.js b/src/components/NoticeIcon/index.js deleted file mode 100644 index 5ba4a70e1e..0000000000 --- a/src/components/NoticeIcon/index.js +++ /dev/null @@ -1,141 +0,0 @@ -import React, { PureComponent, Fragment } from 'react'; -import ReactDOM from 'react-dom'; -import { Icon, Tabs, Badge, Spin } from 'antd'; -import classNames from 'classnames'; -import HeaderDropdown from '../HeaderDropdown'; -import List from './NoticeList'; -import styles from './index.less'; - -const { TabPane } = Tabs; - -export default class NoticeIcon extends PureComponent { - static Tab = TabPane; - - static defaultProps = { - onItemClick: () => {}, - onPopupVisibleChange: () => {}, - onTabChange: () => {}, - onClear: () => {}, - onViewMore: () => {}, - loading: false, - clearClose: false, - locale: { - emptyText: 'No notifications', - clear: 'Clear', - viewMore: 'More', - }, - emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg', - }; - - state = { - visible: false, - }; - - onItemClick = (item, tabProps) => { - const { onItemClick } = this.props; - const { clickClose } = item; - onItemClick(item, tabProps); - if (clickClose) { - this.popover.click(); - } - }; - - onClear = name => { - const { onClear, clearClose } = this.props; - onClear(name); - if (clearClose) { - this.popover.click(); - } - }; - - onTabChange = tabType => { - const { onTabChange } = this.props; - onTabChange(tabType); - }; - - onViewMore = (tabProps, event) => { - const { onViewMore } = this.props; - onViewMore(tabProps, event); - }; - - getNotificationBox() { - const { children, loading, locale } = this.props; - if (!children) { - return null; - } - const panes = React.Children.map(children, child => { - const { list, title, count, emptyText, emptyImage, showClear, showViewMore } = child.props; - const len = list && list.length ? list.length : 0; - const msgCount = count || count === 0 ? count : len; - const localeTitle = locale[title] || title; - const tabTitle = msgCount > 0 ? `${localeTitle} (${msgCount})` : localeTitle; - return ( - - this.onClear(title)} - onClick={item => this.onItemClick(item, child.props)} - onViewMore={event => this.onViewMore(child.props, event)} - showClear={showClear} - showViewMore={showViewMore} - title={title} - /> - - ); - }); - return ( - - - - {panes} - - - - ); - } - - handleVisibleChange = visible => { - const { onPopupVisibleChange } = this.props; - this.setState({ visible }); - onPopupVisibleChange(visible); - }; - - render() { - const { className, count, popupVisible, bell } = this.props; - const { visible } = this.state; - const noticeButtonClass = classNames(className, styles.noticeButton); - const notificationBox = this.getNotificationBox(); - const NoticeBellIcon = bell || ; - const trigger = ( - - - {NoticeBellIcon} - - - ); - if (!notificationBox) { - return trigger; - } - const popoverProps = {}; - if ('popupVisible' in this.props) { - popoverProps.visible = popupVisible; - } - return ( - (this.popover = ReactDOM.findDOMNode(node))} // eslint-disable-line - > - {trigger} - - ); - } -} diff --git a/src/components/NoticeIcon/index.tsx b/src/components/NoticeIcon/index.tsx new file mode 100644 index 0000000000..4ead5bf6f0 --- /dev/null +++ b/src/components/NoticeIcon/index.tsx @@ -0,0 +1,168 @@ +import React, { Component } from 'react'; +import { Icon, Tabs, Badge, Spin } from 'antd'; +import classNames from 'classnames'; +import HeaderDropdown from '../HeaderDropdown'; +import NoticeList, { NoticeIconTabProps } from './NoticeList'; +import styles from './index.less'; + +const { TabPane } = Tabs; + +export interface NoticeIconData { + avatar?: string | React.ReactNode; + title?: React.ReactNode; + description?: React.ReactNode; + datetime?: React.ReactNode; + extra?: React.ReactNode; + style?: React.CSSProperties; + key?: string | number; + read?: boolean; +} + +export interface NoticeIconProps { + count?: number; + bell?: React.ReactNode; + className?: string; + loading?: boolean; + onClear?: (tabName: string, tabKey: string) => void; + onItemClick?: (item: NoticeIconData, tabProps: NoticeIconTabProps) => void; + onViewMore?: (tabProps: NoticeIconTabProps, e: MouseEvent) => void; + onTabChange?: (tabTile: string) => void; + style?: React.CSSProperties; + onPopupVisibleChange?: (visible: boolean) => void; + popupVisible?: boolean; + clearText?: string; + viewMoreText?: string; + clearClose?: boolean; + children: React.ReactElement[]; +} + +export default class NoticeIcon extends Component { + public static Tab: typeof NoticeList = NoticeList; + + static defaultProps = { + onItemClick: () => {}, + onPopupVisibleChange: () => {}, + onTabChange: () => {}, + onClear: () => {}, + onViewMore: () => {}, + loading: false, + clearClose: false, + emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg', + }; + + state = { + visible: false, + }; + + onItemClick = (item: NoticeIconData, tabProps: NoticeIconTabProps) => { + const { onItemClick } = this.props; + if (onItemClick) { + onItemClick(item, tabProps); + } + }; + + onClear = (name: string, key: string) => { + const { onClear } = this.props; + if (onClear) { + onClear(name, key); + } + }; + + onTabChange = (tabType: string) => { + const { onTabChange } = this.props; + if (onTabChange) { + onTabChange(tabType); + } + }; + + onViewMore = (tabProps: NoticeIconTabProps, event: MouseEvent) => { + const { onViewMore } = this.props; + if (onViewMore) { + onViewMore(tabProps, event); + } + }; + + getNotificationBox() { + const { children, loading, clearText, viewMoreText } = this.props; + if (!children) { + return null; + } + const panes = React.Children.map(children, (child: React.ReactElement) => { + if (!child) { + return null; + } + const { list, title, count, tabKey, showClear, showViewMore } = child.props; + const len = list && list.length ? list.length : 0; + const msgCount = count || count === 0 ? count : len; + const tabTitle: string = msgCount > 0 ? `${title} (${msgCount})` : title; + return ( + + this.onClear(title, tabKey)} + onClick={item => this.onItemClick(item, child.props)} + onViewMore={event => this.onViewMore(child.props, event)} + showClear={showClear} + showViewMore={showViewMore} + title={title} + {...child.props} + /> + + ); + }); + return ( + + + {panes} + + + ); + } + + handleVisibleChange = (visible: boolean) => { + const { onPopupVisibleChange } = this.props; + this.setState({ visible }); + if (onPopupVisibleChange) { + onPopupVisibleChange(visible); + } + }; + + render() { + const { className, count, popupVisible, bell } = this.props; + const { visible } = this.state; + const noticeButtonClass = classNames(className, styles.noticeButton); + const notificationBox = this.getNotificationBox(); + const NoticeBellIcon = bell || ; + const trigger = ( + + + {NoticeBellIcon} + + + ); + if (!notificationBox) { + return trigger; + } + const popoverProps: { + visible?: boolean; + } = {}; + if ('popupVisible' in this.props) { + popoverProps.visible = popupVisible; + } + return ( + + {trigger} + + ); + } +} diff --git a/src/components/NoticeIcon/index.zh-CN.md b/src/components/NoticeIcon/index.zh-CN.md deleted file mode 100644 index bd87cb9207..0000000000 --- a/src/components/NoticeIcon/index.zh-CN.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: NoticeIcon -subtitle: 通知菜单 -cols: 1 -order: 9 ---- - -用在导航工具栏上,作为整个产品统一的通知中心。 - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| count | 图标上的消息总数 | number | - | -| bell | translate this please -> Change the bell Icon | ReactNode | `` | -| loading | 弹出卡片加载状态 | boolean | `false` | -| onClear | 点击清空按钮的回调 | function(tabName) | - | -| onItemClick | 点击列表项的回调 | function(item, tabProps) | - | -| onPopupVisibleChange | 弹出卡片显隐的回调 | function(visible) | - | -| onTabChange | 切换页签的回调 | function(tabTitle) | - | -| onViewMore | 点击查看更多的回调 | function(tabProps, event) | - | -| popupVisible | 控制弹层显隐 | boolean | - | -| locale | 默认文案 | Object | `{ emptyText: 'No notifications', clear: 'Clear', viewMore: 'Loading more' }` | -| clearClose | 点击清空按钮后关闭通知菜单 | boolean | `false` | - -### NoticeIcon.Tab - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| count | 当前 Tab 未读消息数量 | number | list.length | -| emptyText | 针对每个 Tab 定制空数据文案 | ReactNode | - | -| emptyImage | 针对每个 Tab 定制空数据图片 | string | - | -| list | 列表数据,格式参照下表 | Array | `[]` | -| showClear | 是否显示清空按钮 | boolean | `true` | -| showViewMore | 是否显示查看更多按钮 | boolean | `false` | -| title | 消息分类的页签标题,实际的文案是 `locale[title] || title` | string | - | - -### Tab data - -| 参数 | 说明 | 类型 | 默认值 | -| ----------- | ------------------------ | ------------------- | ------- | -| avatar | 头像图片链接 | string \| ReactNode | - | -| title | 标题 | ReactNode | - | -| description | 描述信息 | ReactNode | - | -| datetime | 时间戳 | ReactNode | - | -| extra | 额外信息,在列表项右上角 | ReactNode | - | -| clickClose | 点击列表项关闭通知菜单 | boolean | `false` | diff --git a/src/components/NumberInfo/demo/basic.md b/src/components/NumberInfo/demo/basic.md deleted file mode 100644 index 28c212c7e1..0000000000 --- a/src/components/NumberInfo/demo/basic.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -order: 0 -title: - zh-CN: 演示 - en-US: Demo ---- - -## zh-CN - -各种数据文案的展现方式。 - -## en-US - -Used for presenting various numerical data. - -```jsx -import NumberInfo from 'ant-design-pro/lib/NumberInfo'; -import numeral from 'numeral'; - -ReactDOM.render( -
    - Visits this week} - total={numeral(12321).format('0,0')} - status="up" - subTotal={17.1} - /> -
    , - mountNode -); -``` diff --git a/src/components/NumberInfo/index.d.ts b/src/components/NumberInfo/index.d.ts deleted file mode 100644 index 6636db9152..0000000000 --- a/src/components/NumberInfo/index.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -export interface NumberInfoProps { - title?: React.ReactNode | string; - subTitle?: React.ReactNode | string; - total?: React.ReactNode | string; - status?: 'up' | 'down'; - theme?: string; - gap?: number; - subTotal?: number; - suffix?: string; - style?: React.CSSProperties; -} - -export default class NumberInfo extends React.Component {} diff --git a/src/components/NumberInfo/index.en-US.md b/src/components/NumberInfo/index.en-US.md deleted file mode 100644 index 001bf5fa26..0000000000 --- a/src/components/NumberInfo/index.en-US.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: NumberInfo -cols: 1 -order: 10 ---- - -Often used in data cards for highlighting the business data. - -## API - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| title | title | ReactNode\|string | - | -| subTitle | subtitle | ReactNode\|string | - | -| total | total amount | ReactNode\|string | - | -| subTotal | total amount of additional information | ReactNode\|string | - | -| status | increase state | 'up \| down' | - | -| theme | state style | string | 'light' | -| gap | set the spacing (pixels) between numbers and descriptions | number | 8 | diff --git a/src/components/NumberInfo/index.js b/src/components/NumberInfo/index.js deleted file mode 100644 index 717aee9dd7..0000000000 --- a/src/components/NumberInfo/index.js +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import { Icon } from 'antd'; -import classNames from 'classnames'; -import styles from './index.less'; - -const NumberInfo = ({ theme, title, subTitle, total, subTotal, status, suffix, gap, ...rest }) => ( -
    - {title && ( -
    - {title} -
    - )} - {subTitle && ( -
    - {subTitle} -
    - )} -
    - - {total} - {suffix && {suffix}} - - {(status || subTotal) && ( - - {subTotal} - {status && } - - )} -
    -
    -); - -export default NumberInfo; diff --git a/src/components/NumberInfo/index.less b/src/components/NumberInfo/index.less deleted file mode 100644 index 4a77288cc2..0000000000 --- a/src/components/NumberInfo/index.less +++ /dev/null @@ -1,68 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.numberInfo { - .suffix { - margin-left: 4px; - color: @text-color; - font-size: 16px; - font-style: normal; - } - .numberInfoTitle { - margin-bottom: 16px; - color: @text-color; - font-size: @font-size-lg; - transition: all 0.3s; - } - .numberInfoSubTitle { - height: 22px; - overflow: hidden; - color: @text-color-secondary; - font-size: @font-size-base; - line-height: 22px; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - } - .numberInfoValue { - margin-top: 4px; - overflow: hidden; - font-size: 0; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - & > span { - display: inline-block; - height: 32px; - margin-right: 32px; - color: @heading-color; - font-size: 24px; - line-height: 32px; - } - .subTotal { - margin-right: 0; - color: @text-color-secondary; - font-size: @font-size-lg; - vertical-align: top; - i { - margin-left: 4px; - font-size: 12px; - transform: scale(0.82); - } - :global { - .anticon-caret-up { - color: @red-6; - } - .anticon-caret-down { - color: @green-6; - } - } - } - } -} -.numberInfolight { - .numberInfoValue { - & > span { - color: @text-color; - } - } -} diff --git a/src/components/NumberInfo/index.zh-CN.md b/src/components/NumberInfo/index.zh-CN.md deleted file mode 100644 index 4229210c5e..0000000000 --- a/src/components/NumberInfo/index.zh-CN.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: NumberInfo -subtitle: 数据文本 -cols: 1 -order: 10 ---- - -常用在数据卡片中,用于突出展示某个业务数据。 - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| -------- | -------------------------------- | ----------------- | ------- | -| title | 标题 | ReactNode\|string | - | -| subTitle | 子标题 | ReactNode\|string | - | -| total | 总量 | ReactNode\|string | - | -| subTotal | 子总量 | ReactNode\|string | - | -| status | 增加状态 | 'up \| down' | - | -| theme | 状态样式 | string | 'light' | -| gap | 设置数字和描述之间的间距(像素) | number | 8 | diff --git a/src/components/PageHeaderWrapper/GridContent.d.ts b/src/components/PageHeaderWrapper/GridContent.d.ts deleted file mode 100644 index a3d3a308f2..0000000000 --- a/src/components/PageHeaderWrapper/GridContent.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; - -export interface GridContentProps { - contentWidth: string; - children: React.ReactNode; -} - -export default class GridContent extends React.Component {} diff --git a/src/components/PageHeaderWrapper/GridContent.js b/src/components/PageHeaderWrapper/GridContent.js deleted file mode 100644 index 931ea20c91..0000000000 --- a/src/components/PageHeaderWrapper/GridContent.js +++ /dev/null @@ -1,18 +0,0 @@ -import React, { PureComponent } from 'react'; -import { connect } from 'dva'; -import styles from './GridContent.less'; - -class GridContent extends PureComponent { - render() { - const { contentWidth, children } = this.props; - let className = `${styles.main}`; - if (contentWidth === 'Fixed') { - className = `${styles.main} ${styles.wide}`; - } - return
    {children}
    ; - } -} - -export default connect(({ setting }) => ({ - contentWidth: setting.contentWidth, -}))(GridContent); diff --git a/src/components/PageHeaderWrapper/GridContent.less b/src/components/PageHeaderWrapper/GridContent.less deleted file mode 100644 index d5496e9ecb..0000000000 --- a/src/components/PageHeaderWrapper/GridContent.less +++ /dev/null @@ -1,10 +0,0 @@ -.main { - width: 100%; - height: 100%; - min-height: 100%; - transition: 0.3s; - &.wide { - max-width: 1200px; - margin: 0 auto; - } -} diff --git a/src/components/PageHeaderWrapper/breadcrumb.js b/src/components/PageHeaderWrapper/breadcrumb.js deleted file mode 100644 index 4264fef313..0000000000 --- a/src/components/PageHeaderWrapper/breadcrumb.js +++ /dev/null @@ -1,130 +0,0 @@ -import React from 'react'; -import pathToRegexp from 'path-to-regexp'; -import Link from 'umi/link'; -import { formatMessage } from 'umi-plugin-react/locale'; -import { urlToList } from '../_utils/pathTools'; -import { menu } from '../../defaultSettings'; - -// 渲染Breadcrumb 子节点 -// Render the Breadcrumb child node -const itemRender = (route, params, routes, paths) => { - const last = routes.indexOf(route) === routes.length - 1; - // if path is home, use Link。 - if (route.path === '/') { - return {route.breadcrumbName}; - } - return last || !route.component ? ( - {route.breadcrumbName} - ) : ( - {route.breadcrumbName} - ); -}; - -const renderItemLocal = item => { - if (item.locale) { - const name = menu.disableLocal - ? item.name - : formatMessage({ id: item.locale, defaultMessage: item.name }); - return name; - } - return item.name; -}; - -export const getBreadcrumb = (breadcrumbNameMap, url) => { - let breadcrumb = breadcrumbNameMap[url]; - if (!breadcrumb) { - Object.keys(breadcrumbNameMap).forEach(item => { - if (pathToRegexp(item).test(url)) { - breadcrumb = breadcrumbNameMap[item]; - } - }); - } - return breadcrumb || {}; -}; - -export const getBreadcrumbProps = props => { - const { routes, params, location, breadcrumbNameMap } = props; - return { - routes, - params, - routerLocation: location, - breadcrumbNameMap, - }; -}; - -// Generated according to props -const conversionFromProps = props => { - const { breadcrumbList } = props; - return breadcrumbList.map(item => { - const { title, href } = item; - return { - path: href, - breadcrumbName: title, - }; - }); -}; - -const conversionFromLocation = (routerLocation, breadcrumbNameMap, props) => { - const { home } = props; - // Convert the url to an array - const pathSnippets = urlToList(routerLocation.pathname); - // Loop data mosaic routing - const extraBreadcrumbItems = pathSnippets - .map(url => { - const currentBreadcrumb = getBreadcrumb(breadcrumbNameMap, url); - if (currentBreadcrumb.inherited) { - return null; - } - const name = renderItemLocal(currentBreadcrumb); - const { hideInBreadcrumb } = currentBreadcrumb; - return name && !hideInBreadcrumb - ? { - path: url, - breadcrumbName: name, - } - : null; - }) - .filter(item => item !== null); - // Add home breadcrumbs to your head if defined - if (home) { - extraBreadcrumbItems.unshift({ - path: '/', - breadcrumbName: home, - }); - } - return extraBreadcrumbItems; -}; - -/** - * 将参数转化为面包屑 - * Convert parameters into breadcrumbs - */ -export const conversionBreadcrumbList = props => { - const { breadcrumbList } = props; - const { routes, params, routerLocation, breadcrumbNameMap } = getBreadcrumbProps(props); - if (breadcrumbList && breadcrumbList.length) { - return { - routes: conversionFromProps(props), - params, - itemRender, - }; - } - // 如果传入 routes 和 params 属性 - // If pass routes and params attributes - if (routes && params) { - return { - routes: routes.filter(route => route.breadcrumbName), - params, - itemRender, - }; - } - // 根据 location 生成 面包屑 - // Generate breadcrumbs based on location - if (routerLocation && routerLocation.pathname) { - return { - routes: conversionFromLocation(routerLocation, breadcrumbNameMap, props), - itemRender, - }; - } - return {}; -}; diff --git a/src/components/PageHeaderWrapper/index.d.ts b/src/components/PageHeaderWrapper/index.d.ts deleted file mode 100644 index 3ed6d0f98e..0000000000 --- a/src/components/PageHeaderWrapper/index.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -export interface ResultProps { - className?: string; - description?: React.ReactNode; - extra?: React.ReactNode; - style?: React.CSSProperties; - title?: React.ReactNode; - type: 'success' | 'error'; -} - -export default class Result extends React.Component {} diff --git a/src/components/PageHeaderWrapper/index.js b/src/components/PageHeaderWrapper/index.js deleted file mode 100644 index b2849d1ade..0000000000 --- a/src/components/PageHeaderWrapper/index.js +++ /dev/null @@ -1,120 +0,0 @@ -import React from 'react'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import Link from 'umi/link'; -import { PageHeader, Tabs, Typography } from 'antd'; -import { connect } from 'dva'; -import classNames from 'classnames'; -import GridContent from './GridContent'; -import styles from './index.less'; -import MenuContext from '@/layouts/MenuContext'; -import { conversionBreadcrumbList } from './breadcrumb'; - -const { Title } = Typography; - -/** - * render Footer tabList - * In order to be compatible with the old version of the PageHeader - * basically all the functions are implemented. - */ -const renderFooter = ({ tabList, tabActiveKey, onTabChange, tabBarExtraContent }) => { - return tabList && tabList.length ? ( - { - if (onTabChange) { - onTabChange(key); - } - }} - tabBarExtraContent={tabBarExtraContent} - > - {tabList.map(item => ( - - ))} - - ) : null; -}; - -const PageHeaderWrapper = ({ - children, - contentWidth, - fluid, - wrapperClassName, - home, - top, - title, - content, - logo, - extraContent, - hiddenBreadcrumb, - ...restProps -}) => { - return ( -
    - {top} - - {value => { - return ( -
    -
    - - {logo && {logo}} - - {title} - - - } - key="pageheader" - {...restProps} - breadcrumb={ - !hiddenBreadcrumb && - conversionBreadcrumbList({ - ...value, - ...restProps, - ...(home !== null && { - home: , - }), - }) - } - className={styles.pageHeader} - linkElement={Link} - footer={renderFooter(restProps)} - > -
    -
    -
    - {content &&
    {content}
    } - {extraContent &&
    {extraContent}
    } -
    -
    -
    -
    -
    -
    - ); - }} -
    - {children ? ( -
    - {children} -
    - ) : null} -
    - ); -}; - -export default connect(({ setting }) => ({ - contentWidth: setting.contentWidth, -}))(PageHeaderWrapper); diff --git a/src/components/PageHeaderWrapper/index.less b/src/components/PageHeaderWrapper/index.less deleted file mode 100644 index 32a31835ad..0000000000 --- a/src/components/PageHeaderWrapper/index.less +++ /dev/null @@ -1,119 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.children-content { - margin: 24px 24px 0; -} - -.main { - .wrapper { - padding: 16px 24px 0; - background: #fff; - border-bottom: 1px solid #e8e8e8; - - :global { - .ant-page-header { - padding: 0; - } - - .ant-page-header-title-view-extra { - top: 0; - right: 0; - } - } - } - - .wide { - max-width: 1200px; - margin: auto; - } - .detail { - display: flex; - } - - .row { - display: flex; - width: 100%; - } - - .logo { - display: inline-block; - margin-top: -1px; - margin-right: 16px; - vertical-align: middle; - > img { - display: block; - width: 28px; - height: 28px; - border-radius: @border-radius-base; - } - } - - .title-content { - margin-bottom: 16px; - } - - @media screen and (max-width: @screen-sm) { - .children-content { - margin: 24px 0 0; - } - } - - .title, - .content { - flex: auto; - } - - .extraContent, - .main { - flex: 0 1 auto; - } - - .main { - width: 100%; - } - - .title { - margin-bottom: 16px; - } - - .content, - .extraContent { - margin-bottom: 16px; - } - - .extraContent { - min-width: 242px; - margin-left: 88px; - text-align: right; - } - - @media screen and (max-width: @screen-xl) { - .extraContent { - margin-left: 44px; - } - } - - @media screen and (max-width: @screen-lg) { - .extraContent { - margin-left: 20px; - } - } - - @media screen and (max-width: @screen-md) { - .row { - display: block; - } - - .action, - .extraContent { - margin-left: 0; - text-align: left; - } - } - - @media screen and (max-width: @screen-sm) { - .detail { - display: block; - } - } -} diff --git a/src/components/PageLoading/index.js b/src/components/PageLoading/index.tsx similarity index 79% rename from src/components/PageLoading/index.js rename to src/components/PageLoading/index.tsx index 77c0f165f9..0dafd7ad8b 100644 --- a/src/components/PageLoading/index.js +++ b/src/components/PageLoading/index.tsx @@ -3,8 +3,9 @@ import { Spin } from 'antd'; // loading components from code split // https://umijs.org/plugin/umi-plugin-react.html#dynamicimport -export default () => ( +const PageLoding: React.FC = () => (
    ); +export default PageLoding; diff --git a/src/components/Result/demo/classic.md b/src/components/Result/demo/classic.md deleted file mode 100644 index 76bae7173a..0000000000 --- a/src/components/Result/demo/classic.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -order: 1 -title: Classic ---- - -典型结果页面。 - -```jsx -import Result from 'ant-design-pro/lib/Result'; -import { Button, Row, Col, Icon, Steps } from 'antd'; - -const { Step } = Steps; - -const desc1 = ( -
    -
    - 曲丽丽 - -
    -
    2016-12-12 12:32
    -
    -); - -const desc2 = ( -
    -
    - 周毛毛 - -
    -
    - 催一下 -
    -
    -); - -const extra = ( -
    -
    - 项目名称 -
    - - - 项目 ID: - 23421 - - - 负责人: - 曲丽丽 - - - 生效时间: - 2016-12-12 ~ 2017-12-12 - - - - - - - - -
    -); - -const actions = ( -
    - - - -
    -); - -ReactDOM.render( - , - mountNode -); -``` diff --git a/src/components/Result/demo/error.md b/src/components/Result/demo/error.md deleted file mode 100644 index c0848c6d1f..0000000000 --- a/src/components/Result/demo/error.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -order: 2 -title: Failed ---- - -提交失败。 - -```jsx -import Result from 'ant-design-pro/lib/Result'; -import { Button, Icon } from 'antd'; - -const extra = ( -
    -
    - 您提交的内容有如下错误: -
    -
    - - 您的账户已被冻结 - - 立即解冻 - -
    -
    - - 您的账户还不具备申请资格 - - 立即升级 - -
    -
    -); - -const actions = ; - -ReactDOM.render( - , - mountNode -); -``` diff --git a/src/components/Result/demo/structure.md b/src/components/Result/demo/structure.md deleted file mode 100644 index 441d372ddf..0000000000 --- a/src/components/Result/demo/structure.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -order: 0 -title: Structure ---- - -结构包含 `处理结果`,`补充信息` 以及 `操作建议` 三个部分,其中 `处理结果` 由 `提示图标`,`标题` 和 `结果描述` 组成。 - -```jsx -import Result from 'ant-design-pro/lib/Result'; - -ReactDOM.render( - 标题
    } - description={
    结果描述
    } - extra="其他补充信息,自带灰底效果" - actions={
    操作建议,一般放置按钮组
    } - />, - mountNode -); -``` diff --git a/src/components/Result/index.d.ts b/src/components/Result/index.d.ts deleted file mode 100644 index 21c8759b15..0000000000 --- a/src/components/Result/index.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -export interface ResultProps { - actions?: React.ReactNode; - className?: string; - description?: React.ReactNode; - extra?: React.ReactNode; - style?: React.CSSProperties; - title?: React.ReactNode; - type: 'success' | 'error'; -} - -export default class Result extends React.Component {} diff --git a/src/components/Result/index.js b/src/components/Result/index.js deleted file mode 100644 index 89f9f31abe..0000000000 --- a/src/components/Result/index.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import classNames from 'classnames'; -import { Icon } from 'antd'; -import styles from './index.less'; - -export default function Result({ - className, - type, - title, - description, - extra, - actions, - ...restProps -}) { - const iconMap = { - error: , - success: , - }; - const clsString = classNames(styles.result, className); - return ( -
    -
    {iconMap[type]}
    -
    {title}
    - {description &&
    {description}
    } - {extra &&
    {extra}
    } - {actions &&
    {actions}
    } -
    - ); -} diff --git a/src/components/Result/index.less b/src/components/Result/index.less deleted file mode 100644 index 00c958793c..0000000000 --- a/src/components/Result/index.less +++ /dev/null @@ -1,58 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.result { - width: 72%; - margin: 0 auto; - text-align: center; - @media screen and (max-width: @screen-xs) { - width: 100%; - } - - .icon { - margin-bottom: 24px; - font-size: 72px; - line-height: 72px; - - & > .success { - color: @success-color; - } - - & > .error { - color: @error-color; - } - } - - .title { - margin-bottom: 16px; - color: @heading-color; - font-weight: 500; - font-size: 24px; - line-height: 32px; - } - - .description { - margin-bottom: 24px; - color: @text-color-secondary; - font-size: 14px; - line-height: 22px; - } - - .extra { - padding: 24px 40px; - text-align: left; - background: #fafafa; - border-radius: @border-radius-sm; - - @media screen and (max-width: @screen-xs) { - padding: 18px 20px; - } - } - - .actions { - margin-top: 32px; - - button:not(:last-child) { - margin-right: 8px; - } - } -} diff --git a/src/components/Result/index.md b/src/components/Result/index.md deleted file mode 100644 index f875c96e72..0000000000 --- a/src/components/Result/index.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: Result -subtitle: 处理结果 -cols: 1 -order: 12 ---- - -结果页用于对用户进行的一系列任务处理结果进行反馈。 - -## API - -| 参数 | 说明 | 类型 | 默认值 | -| ----------- | ------------------------------------ | ------------------------- | ------ | -| type | 类型,不同类型自带对应的图标 | Enum {'success', 'error'} | - | -| title | 标题 | ReactNode | - | -| description | 结果描述 | ReactNode | - | -| extra | 补充信息,有默认的灰色背景 | ReactNode | - | -| actions | 操作建议,推荐放置跳转链接,按钮组等 | ReactNode | - | diff --git a/src/components/SelectLang/index.d.ts b/src/components/SelectLang/index.d.ts deleted file mode 100644 index d2c53fa32b..0000000000 --- a/src/components/SelectLang/index.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -export interface SelectLangProps { - className?: string; -} - -export default class SelectLang extends React.Component {} diff --git a/src/components/SelectLang/index.js b/src/components/SelectLang/index.js deleted file mode 100644 index 3ce3fb8d36..0000000000 --- a/src/components/SelectLang/index.js +++ /dev/null @@ -1,49 +0,0 @@ -import React, { PureComponent } from 'react'; -import { formatMessage, setLocale, getLocale } from 'umi-plugin-react/locale'; -import { Menu, Icon } from 'antd'; -import classNames from 'classnames'; -import HeaderDropdown from '../HeaderDropdown'; -import styles from './index.less'; - -export default class SelectLang extends PureComponent { - changeLang = ({ key }) => { - setLocale(key); - }; - - render() { - const { className } = this.props; - const selectedLang = getLocale(); - const locales = ['zh-CN', 'zh-TW', 'en-US', 'pt-BR']; - const languageLabels = { - 'zh-CN': '简体中文', - 'zh-TW': '繁体中文', - 'en-US': 'English', - 'pt-BR': 'Português', - }; - const languageIcons = { - 'zh-CN': '🇨🇳', - 'zh-TW': '🇭🇰', - 'en-US': '🇬🇧', - 'pt-BR': '🇧🇷', - }; - const langMenu = ( - - {locales.map(locale => ( - - - {languageIcons[locale]} - {' '} - {languageLabels[locale]} - - ))} - - ); - return ( - - - - - - ); - } -} diff --git a/src/components/SelectLang/index.tsx b/src/components/SelectLang/index.tsx new file mode 100644 index 0000000000..ac8309d953 --- /dev/null +++ b/src/components/SelectLang/index.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { formatMessage, setLocale, getLocale } from 'umi-plugin-react/locale'; +import { Menu, Icon } from 'antd'; +import { ClickParam } from 'antd/es/menu'; +import classNames from 'classnames'; +import HeaderDropdown from '../HeaderDropdown'; +import styles from './index.less'; + +interface SelectLangProps { + className?: string; +} +const SelectLang: React.FC = props => { + const { className } = props; + const selectedLang = getLocale(); + const changeLang = ({ key }: ClickParam) => setLocale(key, false); + const locales = ['zh-CN', 'zh-TW', 'en-US', 'pt-BR']; + const languageLabels = { + 'zh-CN': '简体中文', + 'zh-TW': '繁体中文', + 'en-US': 'English', + 'pt-BR': 'Português', + }; + const languageIcons = { + 'zh-CN': '🇨🇳', + 'zh-TW': '🇭🇰', + 'en-US': '🇬🇧', + 'pt-BR': '🇧🇷', + }; + const langMenu = ( + + {locales.map(locale => ( + + + {languageIcons[locale]} + {' '} + {languageLabels[locale]} + + ))} + + ); + return ( + + + + + + ); +}; + +export default SelectLang; diff --git a/src/components/SettingDrawer/BlockCheckbox.d.ts b/src/components/SettingDrawer/BlockCheckbox.d.ts deleted file mode 100644 index 1012294ec0..0000000000 --- a/src/components/SettingDrawer/BlockCheckbox.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; - -export interface BlockChecboxProps { - value: string; - onChange: (key: string) => void; - list: any[]; -} - -export default class BlockChecbox extends React.Component {} diff --git a/src/components/SettingDrawer/BlockCheckbox.js b/src/components/SettingDrawer/BlockCheckbox.js deleted file mode 100644 index 49af42c730..0000000000 --- a/src/components/SettingDrawer/BlockCheckbox.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { Tooltip, Icon } from 'antd'; -import style from './index.less'; - -const BlockChecbox = ({ value, onChange, list }) => ( -
    - {list.map(item => ( - -
    onChange(item.key)}> - {item.key} -
    - -
    -
    -
    - ))} -
    -); - -export default BlockChecbox; diff --git a/src/components/SettingDrawer/ThemeColor.d.ts b/src/components/SettingDrawer/ThemeColor.d.ts deleted file mode 100644 index 17bc3e8dec..0000000000 --- a/src/components/SettingDrawer/ThemeColor.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; - -export interface TagProps { - color: string; - check: boolean; - className?: string; - onClick?: () => void; -} - -export default class ThemeColor extends React.Component {} diff --git a/src/components/SettingDrawer/ThemeColor.js b/src/components/SettingDrawer/ThemeColor.js deleted file mode 100644 index 9765b737e4..0000000000 --- a/src/components/SettingDrawer/ThemeColor.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from 'react'; -import { Tooltip, Icon } from 'antd'; -import { formatMessage } from 'umi-plugin-react/locale'; -import styles from './ThemeColor.less'; - -const Tag = ({ color, check, ...rest }) => ( -
    - {check ? : ''} -
    -); - -const ThemeColor = ({ colors, title, value, onChange }) => { - let colorList = colors; - if (!colors) { - colorList = [ - { - key: 'dust', - color: '#F5222D', - }, - { - key: 'volcano', - color: '#FA541C', - }, - { - key: 'sunset', - color: '#FAAD14', - }, - { - key: 'cyan', - color: '#13C2C2', - }, - { - key: 'green', - color: '#52C41A', - }, - { - key: 'daybreak', - color: '#1890FF', - }, - { - key: 'geekblue', - color: '#2F54EB', - }, - { - key: 'purple', - color: '#722ED1', - }, - ]; - } - return ( -
    -

    {title}

    -
    - {colorList.map(({ key, color }) => ( - - onChange && onChange(color)} - /> - - ))} -
    -
    - ); -}; - -export default ThemeColor; diff --git a/src/components/SettingDrawer/ThemeColor.less b/src/components/SettingDrawer/ThemeColor.less deleted file mode 100644 index 52e63beaca..0000000000 --- a/src/components/SettingDrawer/ThemeColor.less +++ /dev/null @@ -1,21 +0,0 @@ -.themeColor { - margin-top: 24px; - overflow: hidden; - .title { - margin-bottom: 12px; - color: rgba(0, 0, 0, 0.65); - font-size: 14px; - line-height: 22px; - } - .colorBlock { - float: left; - width: 20px; - height: 20px; - margin-right: 8px; - color: #fff; - font-weight: bold; - text-align: center; - border-radius: 2px; - cursor: pointer; - } -} diff --git a/src/components/SettingDrawer/index.d.ts b/src/components/SettingDrawer/index.d.ts deleted file mode 100644 index 22273089eb..0000000000 --- a/src/components/SettingDrawer/index.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { SiderTheme } from 'antd/es/Layout/Sider'; - -export interface SettingModelState { - navTheme: string | SiderTheme; - primaryColor: string; - layout: string; - contentWidth: string; - fixedHeader: boolean; - autoHideHeader: boolean; - fixSiderbar: boolean; - menu: { disableLocal: boolean }; - title: string; - pwa: boolean; - iconfontUrl: string; - colorWeak: boolean; -} - -export interface SettingDrawerProps { - setting?: SettingModelState; - dispatch?: (args: any) => void; -} - -export default class SettingDrawer extends React.Component {} diff --git a/src/components/SettingDrawer/index.js b/src/components/SettingDrawer/index.js deleted file mode 100644 index dcf341a021..0000000000 --- a/src/components/SettingDrawer/index.js +++ /dev/null @@ -1,258 +0,0 @@ -import React, { Component } from 'react'; -import { Select, message, Drawer, List, Switch, Divider, Icon, Button, Alert, Tooltip } from 'antd'; -import { formatMessage } from 'umi-plugin-react/locale'; -import { CopyToClipboard } from 'react-copy-to-clipboard'; -import { connect } from 'dva'; -import omit from 'omit.js'; -import styles from './index.less'; -import ThemeColor from './ThemeColor'; -import BlockCheckbox from './BlockCheckbox'; - -const { Option } = Select; - -const Body = ({ children, title, style }) => ( -
    -

    {title}

    - {children} -
    -); - -@connect(({ setting }) => ({ setting })) -class SettingDrawer extends Component { - state = { - collapse: false, - }; - - getLayoutSetting = () => { - const { - setting: { contentWidth, fixedHeader, layout, autoHideHeader, fixSiderbar }, - } = this.props; - return [ - { - title: formatMessage({ id: 'app.setting.content-width' }), - action: ( - - ), - }, - { - title: formatMessage({ id: 'app.setting.fixedheader' }), - action: ( - this.changeSetting('fixedHeader', checked)} - /> - ), - }, - { - title: formatMessage({ id: 'app.setting.hideheader' }), - disabled: !fixedHeader, - disabledReason: formatMessage({ id: 'app.setting.hideheader.hint' }), - action: ( - this.changeSetting('autoHideHeader', checked)} - /> - ), - }, - { - title: formatMessage({ id: 'app.setting.fixedsidebar' }), - disabled: layout === 'topmenu', - disabledReason: formatMessage({ id: 'app.setting.fixedsidebar.hint' }), - action: ( - this.changeSetting('fixSiderbar', checked)} - /> - ), - }, - ]; - }; - - changeSetting = (key, value) => { - const { setting } = this.props; - const nextState = { ...setting }; - nextState[key] = value; - if (key === 'layout') { - nextState.contentWidth = value === 'topmenu' ? 'Fixed' : 'Fluid'; - } else if (key === 'fixedHeader' && !value) { - nextState.autoHideHeader = false; - } - this.setState(nextState, () => { - const { dispatch } = this.props; - dispatch({ - type: 'setting/changeSetting', - payload: this.state, - }); - }); - }; - - togglerContent = () => { - const { collapse } = this.state; - this.setState({ collapse: !collapse }); - }; - - renderLayoutSettingItem = item => { - const action = React.cloneElement(item.action, { - disabled: item.disabled, - }); - return ( - - - {item.title} - - - ); - }; - - render() { - const { setting } = this.props; - const { navTheme, primaryColor, layout, colorWeak } = setting; - const { collapse } = this.state; - return ( - - -
    - } - style={{ - zIndex: 999, - }} - > -
    - - this.changeSetting('navTheme', value)} - /> - - - this.changeSetting('primaryColor', color)} - /> - - - - - this.changeSetting('layout', value)} - /> - - - - - - - - this.changeSetting('colorWeak', checked)} - /> - ), - }, - ]} - /> - - - message.success(formatMessage({ id: 'app.setting.copyinfo' }))} - > - - - - {formatMessage({ id: 'app.setting.production.hint' })}{' '} - - src/defaultSettings.js - -
    - } - /> -
    - - ); - } -} - -export default SettingDrawer; diff --git a/src/components/SettingDrawer/index.less b/src/components/SettingDrawer/index.less deleted file mode 100644 index 0654878866..0000000000 --- a/src/components/SettingDrawer/index.less +++ /dev/null @@ -1,81 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.content { - position: relative; - min-height: 100%; - background: #fff; - :global { - .ant-list-item { - span { - flex: 1; - } - } - } -} - -.blockChecbox { - display: flex; - .item { - position: relative; - margin-right: 16px; - // box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); - border-radius: @border-radius-base; - cursor: pointer; - img { - width: 48px; - } - } - .selectIcon { - position: absolute; - top: 0; - right: 0; - width: 100%; - height: 100%; - padding-top: 15px; - padding-left: 24px; - color: @primary-color; - font-weight: bold; - font-size: 14px; - } -} - -.color_block { - display: inline-block; - width: 38px; - height: 22px; - margin: 4px; - margin-right: 12px; - vertical-align: middle; - border-radius: 4px; - cursor: pointer; -} - -.title { - margin-bottom: 12px; - color: @heading-color; - font-size: 14px; - line-height: 22px; -} - -.handle { - position: absolute; - top: 240px; - right: 300px; - z-index: 0; - display: flex; - align-items: center; - justify-content: center; - width: 48px; - height: 48px; - font-size: 16px; - text-align: center; - background: @primary-color; - border-radius: 4px 0 0 4px; - cursor: pointer; - pointer-events: auto; -} - -.productionHint { - margin-top: 16px; - font-size: 12px; -} diff --git a/src/components/SiderMenu/BaseMenu.d.ts b/src/components/SiderMenu/BaseMenu.d.ts deleted file mode 100644 index 79fcf46742..0000000000 --- a/src/components/SiderMenu/BaseMenu.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import * as H from 'history'; -import { SiderTheme, CollapseType } from 'antd/es/Layout/Sider'; - -import { MenuMode } from 'antd/es/menu'; - -export interface BaseMenuProps { - flatMenuKeys?: any[]; - location?: H.Location; - onCollapse?: (collapsed: boolean, type?: CollapseType) => void; - isMobile?: boolean; - openKeys?: any; - theme?: SiderTheme; - mode?: MenuMode; - className?: string; - collapsed?: boolean; - handleOpenChange?: (openKeys: any[]) => void; - menuData?: any[]; - style?: React.CSSProperties; - onOpenChange?: (openKeys: string[]) => void; -} - -export default class BaseMenu extends React.Component {} diff --git a/src/components/SiderMenu/BaseMenu.js b/src/components/SiderMenu/BaseMenu.js deleted file mode 100644 index 87eafb02ef..0000000000 --- a/src/components/SiderMenu/BaseMenu.js +++ /dev/null @@ -1,183 +0,0 @@ -import React, { PureComponent } from 'react'; -import classNames from 'classnames'; -import { Menu, Icon } from 'antd'; -import Link from 'umi/link'; -import { urlToList } from '../_utils/pathTools'; -import { getMenuMatches } from './SiderMenuUtils'; -import { isUrl } from '@/utils/utils'; -import styles from './index.less'; -import IconFont from '@/components/IconFont'; - -const { SubMenu } = Menu; - -// Allow menu.js config icon as string or ReactNode -// icon: 'setting', -// icon: 'icon-geren' #For Iconfont , -// icon: 'http://demo.com/icon.png', -// icon: , -const getIcon = icon => { - if (typeof icon === 'string') { - if (isUrl(icon)) { - return icon} />; - } - if (icon.startsWith('icon-')) { - return ; - } - return ; - } - return icon; -}; - -export default class BaseMenu extends PureComponent { - /** - * 获得菜单子节点 - * @memberof SiderMenu - */ - getNavMenuItems = menusData => { - if (!menusData) { - return []; - } - return menusData - .filter(item => item.name && !item.hideInMenu) - .map(item => this.getSubMenuOrItem(item)) - .filter(item => item); - }; - - // Get the currently selected menu - getSelectedMenuKeys = pathname => { - const { flatMenuKeys } = this.props; - return urlToList(pathname).map(itemPath => getMenuMatches(flatMenuKeys, itemPath).pop()); - }; - - /** - * get SubMenu or Item - */ - getSubMenuOrItem = item => { - // doc: add hideChildrenInMenu - if (item.children && !item.hideChildrenInMenu && item.children.some(child => child.name)) { - const { name } = item; - return ( - - {getIcon(item.icon)} - {name} - - ) : ( - name - ) - } - key={item.path} - > - {this.getNavMenuItems(item.children)} - - ); - } - return {this.getMenuItemPath(item)}; - }; - - /** - * 判断是否是http链接.返回 Link 或 a - * Judge whether it is http link.return a or Link - * @memberof SiderMenu - */ - getMenuItemPath = item => { - const { name } = item; - const itemPath = this.conversionPath(item.path); - const icon = getIcon(item.icon); - const { target } = item; - // Is it a http link - if (/^https?:\/\//.test(itemPath)) { - return ( - - {icon} - {name} - - ); - } - const { location, isMobile, onCollapse } = this.props; - return ( - { - onCollapse(true); - } - : undefined - } - > - {icon} - {name} - - ); - }; - - conversionPath = path => { - if (path && path.indexOf('http') === 0) { - return path; - } - return `/${path || ''}`.replace(/\/+/g, '/'); - }; - - getPopupContainer = (fixedHeader, layout) => { - if (fixedHeader && layout === 'topmenu') { - return this.wrap; - } - return document.body; - }; - - getRef = ref => { - this.wrap = ref; - }; - - render() { - const { - openKeys, - theme, - mode, - location: { pathname }, - className, - collapsed, - fixedHeader, - layout, - } = this.props; - // if pathname can't match, use the nearest parent's key - let selectedKeys = this.getSelectedMenuKeys(pathname); - if (!selectedKeys.length && openKeys) { - selectedKeys = [openKeys[openKeys.length - 1]]; - } - let props = {}; - if (openKeys && !collapsed) { - props = { - openKeys: openKeys.length === 0 ? [...selectedKeys] : openKeys, - }; - } - const { handleOpenChange, style, menuData } = this.props; - const cls = classNames(className, { - 'top-nav-menu': mode === 'horizontal', - }); - - return ( - <> - this.getPopupContainer(fixedHeader, layout)} - > - {this.getNavMenuItems(menuData)} - -
    - - ); - } -} diff --git a/src/components/SiderMenu/SiderMenu.d.ts b/src/components/SiderMenu/SiderMenu.d.ts deleted file mode 100644 index c18162a8df..0000000000 --- a/src/components/SiderMenu/SiderMenu.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import * as H from 'history'; -import { BaseMenuProps } from './BaseMenu'; -import { SiderTheme } from 'antd/es/Layout/Sider'; - -export interface SiderMenuProps extends BaseMenuProps { - logo?: string; - fixSiderbar?: boolean; -} - -export default class SiderMenu extends React.Component {} diff --git a/src/components/SiderMenu/SiderMenu.js b/src/components/SiderMenu/SiderMenu.js deleted file mode 100644 index da9520faa8..0000000000 --- a/src/components/SiderMenu/SiderMenu.js +++ /dev/null @@ -1,99 +0,0 @@ -import React, { PureComponent, Suspense } from 'react'; -import { Layout } from 'antd'; -import classNames from 'classnames'; -import Link from 'umi/link'; -import styles from './index.less'; -import PageLoading from '../PageLoading'; -import { getDefaultCollapsedSubMenus } from './SiderMenuUtils'; -import { title } from '../../defaultSettings'; - -const BaseMenu = React.lazy(() => import('./BaseMenu')); -const { Sider } = Layout; - -let firstMount = true; - -export default class SiderMenu extends PureComponent { - constructor(props) { - super(props); - this.state = { - openKeys: getDefaultCollapsedSubMenus(props), - }; - } - - componentDidMount() { - firstMount = false; - } - - static getDerivedStateFromProps(props, state) { - const { pathname, flatMenuKeysLen } = state; - if (props.location.pathname !== pathname || props.flatMenuKeys.length !== flatMenuKeysLen) { - return { - pathname: props.location.pathname, - flatMenuKeysLen: props.flatMenuKeys.length, - openKeys: getDefaultCollapsedSubMenus(props), - }; - } - return null; - } - - isMainMenu = key => { - const { menuData } = this.props; - return menuData.some(item => { - if (key) { - return item.key === key || item.path === key; - } - return false; - }); - }; - - handleOpenChange = openKeys => { - const moreThanOne = openKeys.filter(openKey => this.isMainMenu(openKey)).length > 1; - this.setState({ - openKeys: moreThanOne ? [openKeys.pop()] : [...openKeys], - }); - }; - - render() { - const { logo, collapsed, onCollapse, fixSiderbar, theme, isMobile } = this.props; - const { openKeys } = this.state; - const defaultProps = collapsed ? {} : { openKeys }; - - const siderClassName = classNames(styles.sider, { - [styles.fixSiderBar]: fixSiderbar, - [styles.light]: theme === 'light', - }); - return ( - { - if (firstMount || !isMobile) { - onCollapse(collapse); - } - }} - width={256} - theme={theme} - className={siderClassName} - > - - }> - - - - ); - } -} diff --git a/src/components/SiderMenu/SiderMenu.test.js b/src/components/SiderMenu/SiderMenu.test.js deleted file mode 100644 index 3d280da08a..0000000000 --- a/src/components/SiderMenu/SiderMenu.test.js +++ /dev/null @@ -1,39 +0,0 @@ -import { getFlatMenuKeys } from './SiderMenuUtils'; - -const menu = [ - { - path: '/dashboard', - children: [ - { - path: '/dashboard/name', - }, - ], - }, - { - path: '/userinfo', - children: [ - { - path: '/userinfo/:id', - children: [ - { - path: '/userinfo/:id/info', - }, - ], - }, - ], - }, -]; - -const flatMenuKeys = getFlatMenuKeys(menu); - -describe('test convert nested menu to flat menu', () => { - it('simple menu', () => { - expect(flatMenuKeys).toEqual([ - '/dashboard', - '/dashboard/name', - '/userinfo', - '/userinfo/:id', - '/userinfo/:id/info', - ]); - }); -}); diff --git a/src/components/SiderMenu/SiderMenuUtils.js b/src/components/SiderMenu/SiderMenuUtils.js deleted file mode 100644 index 6e04ec134d..0000000000 --- a/src/components/SiderMenu/SiderMenuUtils.js +++ /dev/null @@ -1,40 +0,0 @@ -import pathToRegexp from 'path-to-regexp'; -import { urlToList } from '../_utils/pathTools'; - -/** - * Recursively flatten the data - * [{path:string},{path:string}] => {path,path2} - * @param menus - */ -export const getFlatMenuKeys = menuData => { - let keys = []; - menuData.forEach(item => { - keys.push(item.path); - if (item.children) { - keys = keys.concat(getFlatMenuKeys(item.children)); - } - }); - return keys; -}; - -export const getMenuMatches = (flatMenuKeys, path) => - flatMenuKeys.filter(item => { - if (item) { - return pathToRegexp(item).test(path); - } - return false; - }); -/** - * 获得菜单子节点 - * @memberof SiderMenu - */ -export const getDefaultCollapsedSubMenus = props => { - const { - location: { pathname }, - flatMenuKeys, - } = props; - return urlToList(pathname) - .map(item => getMenuMatches(flatMenuKeys, item)[0]) - .filter(item => item) - .reduce((acc, curr) => [...acc, curr], ['/']); -}; diff --git a/src/components/SiderMenu/index.d.ts b/src/components/SiderMenu/index.d.ts deleted file mode 100644 index 383df9e11d..0000000000 --- a/src/components/SiderMenu/index.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import { SiderTheme } from 'antd/es/Layout/Sider'; - -export interface SiderMenuProps { - isMobile: boolean; - menuData: any[]; - collapsed: boolean; - logo?: string; - theme?: SiderTheme; - onCollapse: (payload: boolean) => void; -} - -export default class SiderMenuWrapper extends React.Component {} diff --git a/src/components/SiderMenu/index.js b/src/components/SiderMenu/index.js deleted file mode 100644 index 0be273314d..0000000000 --- a/src/components/SiderMenu/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import { Drawer } from 'antd'; -import SiderMenu from './SiderMenu'; -import { getFlatMenuKeys } from './SiderMenuUtils'; - -const SiderMenuWrapper = React.memo(props => { - const { isMobile, menuData, collapsed, onCollapse } = props; - const flatMenuKeys = getFlatMenuKeys(menuData); - return isMobile ? ( - onCollapse(true)} - style={{ - padding: 0, - height: '100vh', - }} - > - - - ) : ( - - ); -}); - -export default SiderMenuWrapper; diff --git a/src/components/SiderMenu/index.less b/src/components/SiderMenu/index.less deleted file mode 100644 index 88722c87e9..0000000000 --- a/src/components/SiderMenu/index.less +++ /dev/null @@ -1,105 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -@nav-header-height: @layout-header-height; - -.logo { - position: relative; - height: @nav-header-height; - padding-left: (@menu-collapsed-width - 32px) / 2; - overflow: hidden; - line-height: @nav-header-height; - background: #002140; - transition: all 0.3s; - img { - display: inline-block; - height: 32px; - vertical-align: middle; - } - h1 { - display: inline-block; - margin: 0 0 0 12px; - color: white; - font-weight: 600; - font-size: 20px; - font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif; - vertical-align: middle; - } -} -.sider { - position: relative; - z-index: 10; - min-height: 100vh; - box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35); - &.fixSiderBar { - position: fixed; - top: 0; - left: 0; - box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05); - :global { - .ant-menu-root { - height: ~'calc(100vh - @{nav-header-height})'; - overflow-y: auto; - } - .ant-menu-inline { - border-right: 0; - .ant-menu-item, - .ant-menu-submenu-title { - width: 100%; - } - } - } - } - &.light { - background-color: white; - box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05); - .logo { - background: white; - box-shadow: 1px 1px 0 0 @border-color-split; - h1 { - color: @primary-color; - } - } - :global(.ant-menu-light) { - border-right-color: transparent; - } - } -} - -.icon { - width: 14px; - vertical-align: baseline; -} - -:global { - .top-nav-menu li.ant-menu-item { - height: @nav-header-height; - line-height: @nav-header-height; - } - .drawer .drawer-content { - background: #001529; - } - .ant-menu-inline-collapsed { - & > .ant-menu-item .sider-menu-item-img + span, - & - > .ant-menu-item-group - > .ant-menu-item-group-list - > .ant-menu-item - .sider-menu-item-img - + span, - & > .ant-menu-submenu > .ant-menu-submenu-title .sider-menu-item-img + span { - display: inline-block; - max-width: 0; - opacity: 0; - } - } - .ant-menu-item .sider-menu-item-img + span, - .ant-menu-submenu-title .sider-menu-item-img + span { - opacity: 1; - transition: opacity 0.3s @ease-in-out, width 0.3s @ease-in-out; - } - .ant-drawer-left { - .ant-drawer-body { - padding: 0; - } - } -} diff --git a/src/components/StandardFormRow/index.d.ts b/src/components/StandardFormRow/index.d.ts deleted file mode 100644 index de06c9b829..0000000000 --- a/src/components/StandardFormRow/index.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -export interface StandardFormRowProps { - title: string; - last?: boolean; - block?: boolean; - grid?: boolean; - style?: React.CSSProperties; -} - -export default class StandardFormRow extends React.Component {} diff --git a/src/components/StandardFormRow/index.js b/src/components/StandardFormRow/index.js deleted file mode 100644 index 8cb0e444e6..0000000000 --- a/src/components/StandardFormRow/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import classNames from 'classnames'; -import styles from './index.less'; - -const StandardFormRow = ({ title, children, last, block, grid, ...rest }) => { - const cls = classNames(styles.standardFormRow, { - [styles.standardFormRowBlock]: block, - [styles.standardFormRowLast]: last, - [styles.standardFormRowGrid]: grid, - }); - - return ( -
    - {title && ( -
    - {title} -
    - )} -
    {children}
    -
    - ); -}; - -export default StandardFormRow; diff --git a/src/components/StandardFormRow/index.less b/src/components/StandardFormRow/index.less deleted file mode 100644 index 042723336b..0000000000 --- a/src/components/StandardFormRow/index.less +++ /dev/null @@ -1,72 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.standardFormRow { - display: flex; - margin-bottom: 16px; - padding-bottom: 16px; - border-bottom: 1px dashed @border-color-split; - :global { - .ant-form-item { - margin-right: 24px; - } - .ant-form-item-label label { - margin-right: 0; - color: @text-color; - } - .ant-form-item-label, - .ant-form-item-control { - padding: 0; - line-height: 32px; - } - } - .label { - flex: 0 0 auto; - margin-right: 24px; - color: @heading-color; - font-size: @font-size-base; - text-align: right; - & > span { - display: inline-block; - height: 32px; - line-height: 32px; - &::after { - content: ':'; - } - } - } - .content { - flex: 1 1 0; - :global { - .ant-form-item:last-child { - margin-right: 0; - } - } - } -} - -.standardFormRowLast { - margin-bottom: 0; - padding-bottom: 0; - border: none; -} - -.standardFormRowBlock { - :global { - .ant-form-item, - div.ant-form-item-control-wrapper { - display: block; - } - } -} - -.standardFormRowGrid { - :global { - .ant-form-item, - div.ant-form-item-control-wrapper { - display: block; - } - .ant-form-item-label { - float: left; - } - } -} diff --git a/src/components/StandardTable/index.d.ts b/src/components/StandardTable/index.d.ts deleted file mode 100644 index d9addeffae..0000000000 --- a/src/components/StandardTable/index.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import { PaginationConfig, SorterResult, TableCurrentDataSource } from 'antd/lib/table'; - -export interface StandardTableProps { - columns: any; - onSelectRow: (row: any) => void; - data: any; - rowKey?: string; - selectedRows: any[]; - onChange?: ( - pagination: PaginationConfig, - filters: Record, - sorter: SorterResult, - extra?: TableCurrentDataSource - ) => void; - loading?: boolean; -} - -export default class StandardTable extends React.Component {} diff --git a/src/components/StandardTable/index.js b/src/components/StandardTable/index.js deleted file mode 100644 index c0c17251ed..0000000000 --- a/src/components/StandardTable/index.js +++ /dev/null @@ -1,121 +0,0 @@ -import React, { PureComponent, Fragment } from 'react'; -import { Table, Alert } from 'antd'; -import styles from './index.less'; - -function initTotalList(columns) { - const totalList = []; - columns.forEach(column => { - if (column.needTotal) { - totalList.push({ ...column, total: 0 }); - } - }); - return totalList; -} - -class StandardTable extends PureComponent { - constructor(props) { - super(props); - const { columns } = props; - const needTotalList = initTotalList(columns); - - this.state = { - selectedRowKeys: [], - needTotalList, - }; - } - - static getDerivedStateFromProps(nextProps) { - // clean state - if (nextProps.selectedRows.length === 0) { - const needTotalList = initTotalList(nextProps.columns); - return { - selectedRowKeys: [], - needTotalList, - }; - } - return null; - } - - handleRowSelectChange = (selectedRowKeys, selectedRows) => { - let { needTotalList } = this.state; - needTotalList = needTotalList.map(item => ({ - ...item, - total: selectedRows.reduce((sum, val) => sum + parseFloat(val[item.dataIndex], 10), 0), - })); - const { onSelectRow } = this.props; - if (onSelectRow) { - onSelectRow(selectedRows); - } - - this.setState({ selectedRowKeys, needTotalList }); - }; - - handleTableChange = (pagination, filters, sorter) => { - const { onChange } = this.props; - if (onChange) { - onChange(pagination, filters, sorter); - } - }; - - cleanSelectedKeys = () => { - this.handleRowSelectChange([], []); - }; - - render() { - const { selectedRowKeys, needTotalList } = this.state; - const { data = {}, rowKey, ...rest } = this.props; - const { list = [], pagination } = data; - - const paginationProps = { - showSizeChanger: true, - showQuickJumper: true, - ...pagination, - }; - - const rowSelection = { - selectedRowKeys, - onChange: this.handleRowSelectChange, - getCheckboxProps: record => ({ - disabled: record.disabled, - }), - }; - - return ( -
    -
    - - 已选择 {selectedRowKeys.length} 项   - {needTotalList.map(item => ( - - {item.title} - 总计  - - {item.render ? item.render(item.total) : item.total} - - - ))} - - 清空 - - - } - type="info" - showIcon - /> -
    - - - ); - } -} - -export default StandardTable; diff --git a/src/components/StandardTable/index.less b/src/components/StandardTable/index.less deleted file mode 100644 index 817be991fe..0000000000 --- a/src/components/StandardTable/index.less +++ /dev/null @@ -1,13 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.standardTable { - :global { - .ant-table-pagination { - margin-top: 24px; - } - } - - .tableAlert { - margin-bottom: 16px; - } -} diff --git a/src/components/TagSelect/TagSelectOption.d.ts b/src/components/TagSelect/TagSelectOption.d.ts deleted file mode 100644 index 3343d744ce..0000000000 --- a/src/components/TagSelect/TagSelectOption.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - -export interface TagSelectOptionProps { - value?: string | number; - style?: React.CSSProperties; - checked?: boolean; - onChange?: (value: string | number, state: boolean) => void; -} - -export default class TagSelectOption extends React.Component { - public static isTagSelectOption?: boolean; -} diff --git a/src/components/TagSelect/demo/controlled.md b/src/components/TagSelect/demo/controlled.md deleted file mode 100644 index 4e9defa782..0000000000 --- a/src/components/TagSelect/demo/controlled.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -order: 3 -title: 受控模式 ---- - -结合 `Tag` 的 `TagSelect` 组件,方便的应用于筛选类目的业务场景中。 - -```jsx -import { Button } from 'antd'; -import TagSelect from 'ant-design-pro/lib/TagSelect'; - -class Demo extends React.Component { - state = { - value: ['cat1'], - }; - handleFormSubmit = value => { - this.setState({ - value, - }); - }; - checkAll = () => { - this.setState({ - value: ['cat1', 'cat2', 'cat3', 'cat4', 'cat5', 'cat6'], - }); - }; - render() { - return ( -
    - -
    - - 类目一 - 类目二 - 类目三 - 类目四 - 类目五 - 类目六 - -
    -
    - ); - } -} - -ReactDOM.render(, mountNode); -``` diff --git a/src/components/TagSelect/demo/expandable.md b/src/components/TagSelect/demo/expandable.md deleted file mode 100644 index af595664eb..0000000000 --- a/src/components/TagSelect/demo/expandable.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -order: 1 -title: 可展开和收起 ---- - -使用 `expandable` 属性,让标签组可以收起,避免过高。 - -```jsx -import TagSelect from 'ant-design-pro/lib/TagSelect'; - -function handleFormSubmit(checkedValue) { - console.log(checkedValue); -} - -ReactDOM.render( - - 类目一 - 类目二 - 类目三 - 类目四 - 类目五 - 类目六 - 类目七 - 类目八 - 类目九 - 类目十 - 类目十一 - 类目十二 - , - mountNode -); -``` diff --git a/src/components/TagSelect/demo/simple.md b/src/components/TagSelect/demo/simple.md deleted file mode 100644 index 9b8f9ad314..0000000000 --- a/src/components/TagSelect/demo/simple.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -order: 0 -title: 基础样例 ---- - -结合 `Tag` 的 `TagSelect` 组件,方便的应用于筛选类目的业务场景中。 - -```jsx -import TagSelect from 'ant-design-pro/lib/TagSelect'; - -function handleFormSubmit(checkedValue) { - console.log(checkedValue); -} - -ReactDOM.render( - - 类目一 - 类目二 - 类目三 - 类目四 - 类目五 - 类目六 - , - mountNode -); -``` diff --git a/src/components/TagSelect/index.d.ts b/src/components/TagSelect/index.d.ts deleted file mode 100644 index c225a86fe6..0000000000 --- a/src/components/TagSelect/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import TagSelectOption, { TagSelectOptionProps } from './TagSelectOption'; - -export interface TagSelectProps { - onChange?: (value: string[]) => void; - expandable?: boolean; - value?: string[] | number[]; - style?: React.CSSProperties; - hideCheckAll?: boolean; - actionsText?: { - expandText?: React.ReactNode; - collapseText?: React.ReactNode; - selectAllText?: React.ReactNode; - }; - className: string; - Option: TagSelectOptionProps; - children: React.ReactElement | Array>; -} - -export default class TagSelect extends React.Component { - public static Option: typeof TagSelectOption; - private children: - | React.ReactElement - | Array>; -} diff --git a/src/components/TagSelect/index.js b/src/components/TagSelect/index.js deleted file mode 100644 index 6d0394dd34..0000000000 --- a/src/components/TagSelect/index.js +++ /dev/null @@ -1,143 +0,0 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { Tag, Icon } from 'antd'; - -import styles from './index.less'; - -const { CheckableTag } = Tag; - -const TagSelectOption = ({ children, checked, onChange, value }) => ( - onChange(value, state)}> - {children} - -); - -TagSelectOption.isTagSelectOption = true; - -class TagSelect extends Component { - static propTypes = { - actionsText: PropTypes.object, - hideCheckAll: PropTypes.bool, - }; - - static defaultProps = { - hideCheckAll: false, - actionsText: { - expandText: 'Expand', - collapseText: 'Collapse', - selectAllText: 'All', - }, - }; - - constructor(props) { - super(props); - this.state = { - expand: false, - value: props.value || props.defaultValue || [], - }; - } - - static getDerivedStateFromProps(nextProps) { - if ('value' in nextProps) { - return { value: nextProps.value || [] }; - } - return null; - } - - onChange = value => { - const { onChange } = this.props; - if (!('value' in this.props)) { - this.setState({ value }); - } - if (onChange) { - onChange(value); - } - }; - - onSelectAll = checked => { - let checkedTags = []; - if (checked) { - checkedTags = this.getAllTags(); - } - this.onChange(checkedTags); - }; - - getAllTags() { - let { children } = this.props; - children = React.Children.toArray(children); - const checkedTags = children - .filter(child => this.isTagSelectOption(child)) - .map(child => child.props.value); - return checkedTags || []; - } - - handleTagChange = (value, checked) => { - const { value: StateValue } = this.state; - const checkedTags = [...StateValue]; - - const index = checkedTags.indexOf(value); - if (checked && index === -1) { - checkedTags.push(value); - } else if (!checked && index > -1) { - checkedTags.splice(index, 1); - } - this.onChange(checkedTags); - }; - - handleExpand = () => { - const { expand } = this.state; - this.setState({ - expand: !expand, - }); - }; - - isTagSelectOption = node => - node && - node.type && - (node.type.isTagSelectOption || node.type.displayName === 'TagSelectOption'); - - render() { - const { value, expand } = this.state; - const { children, hideCheckAll, className, style, expandable, actionsText } = this.props; - const checkedAll = this.getAllTags().length === value.length; - const { expandText = 'Expand', collapseText = 'Collapse', selectAllText = 'All' } = - actionsText === null ? {} : actionsText; - - const cls = classNames(styles.tagSelect, className, { - [styles.hasExpandTag]: expandable, - [styles.expanded]: expand, - }); - - return ( -
    - {hideCheckAll ? null : ( - - {selectAllText} - - )} - {value && - React.Children.map(children, child => { - if (this.isTagSelectOption(child)) { - return React.cloneElement(child, { - key: `tag-select-${child.props.value}`, - value: child.props.value, - checked: value.indexOf(child.props.value) > -1, - onChange: this.handleTagChange, - }); - } - return child; - })} - {expandable && ( - - {expand ? collapseText : expandText} - - )} -
    - ); - } -} - -TagSelect.Option = TagSelectOption; - -export default TagSelect; diff --git a/src/components/TagSelect/index.less b/src/components/TagSelect/index.less deleted file mode 100644 index 9369465313..0000000000 --- a/src/components/TagSelect/index.less +++ /dev/null @@ -1,33 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.tagSelect { - position: relative; - max-height: 32px; - margin-left: -8px; - overflow: hidden; - line-height: 32px; - transition: all 0.3s; - user-select: none; - :global { - .ant-tag { - margin-right: 24px; - padding: 0 8px; - font-size: @font-size-base; - } - } - &.expanded { - max-height: 200px; - transition: all 0.3s; - } - .trigger { - position: absolute; - top: 0; - right: 0; - i { - font-size: 12px; - } - } - &.hasExpandTag { - padding-right: 50px; - } -} diff --git a/src/components/TagSelect/index.md b/src/components/TagSelect/index.md deleted file mode 100644 index d3beaa41a9..0000000000 --- a/src/components/TagSelect/index.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: TagSelect -subtitle: 标签选择器 -cols: 1 -order: 13 ---- - -可进行多选,带折叠收起和展开更多功能,常用于对列表进行筛选。 - -## API - -### TagSelect - -| 参数 | 说明 | 类型 | 默认值 | -| ------------ | ------------------------- | --------------------- | ------ | -| value | 选中的项 | string[] \| number[] | | -| defaultValue | 默认选中的项 | string[] \| number[] | | -| onChange | 标签选择的回调函数 | Function(checkedTags) | | -| expandable | 是否展示 `展开/收起` 按钮 | Boolean | false | -| hideCheckAll | 隐藏 `全部` 按钮 | Boolean | false | - -### TagSelectOption - -| 参数 | 说明 | 类型 | 默认值 | -| -------- | -------------- | ------------------- | ------ | -| value | TagSelect 的值 | string\| number | - | -| children | tag 的内容 | string \| ReactNode | - | diff --git a/src/components/TopNavHeader/index.d.ts b/src/components/TopNavHeader/index.d.ts deleted file mode 100644 index 2d6631be39..0000000000 --- a/src/components/TopNavHeader/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { SiderTheme, CollapseType } from 'antd/es/Layout/Sider'; -import { MenuMode } from 'antd/es/menu'; - -export interface TopNavHeaderProps { - theme: SiderTheme; - contentWidth?: string; - menuData?: any[]; - logo?: string; - mode?: MenuMode; - flatMenuKeys?: any[]; - onCollapse?: (collapsed: boolean, type?: CollapseType) => void; - isMobile?: boolean; - openKeys?: any; - className?: string; - collapsed?: boolean; - handleOpenChange?: (openKeys: any[]) => void; - style?: React.CSSProperties; - onOpenChange?: (openKeys: string[]) => void; - onNoticeClear?: (type: string) => void; - onMenuClick?: ({ key: string }) => void; - onNoticeVisibleChange?: (b: boolean) => void; -} - -export default class TopNavHeader extends React.Component {} diff --git a/src/components/TopNavHeader/index.js b/src/components/TopNavHeader/index.js deleted file mode 100644 index 0b6440e6d4..0000000000 --- a/src/components/TopNavHeader/index.js +++ /dev/null @@ -1,56 +0,0 @@ -import React, { PureComponent } from 'react'; -import Link from 'umi/link'; -import RightContent from '../GlobalHeader/RightContent'; -import BaseMenu from '../SiderMenu/BaseMenu'; -import { getFlatMenuKeys } from '../SiderMenu/SiderMenuUtils'; -import styles from './index.less'; -import { title } from '../../defaultSettings'; - -export default class TopNavHeader extends PureComponent { - state = { - maxWidth: undefined, - }; - - static getDerivedStateFromProps(props) { - return { - maxWidth: - (props.contentWidth === 'Fixed' && window.innerWidth > 1200 ? 1200 : window.innerWidth) - - 280 - - 120 - - 40, - }; - } - - render() { - const { theme, contentWidth, menuData, logo } = this.props; - const { maxWidth } = this.state; - const flatMenuKeys = getFlatMenuKeys(menuData); - return ( -
    -
    { - this.maim = ref; - }} - className={`${styles.main} ${contentWidth === 'Fixed' ? styles.wide : ''}`} - > -
    - -
    - -
    -
    - -
    -
    - ); - } -} diff --git a/src/components/TopNavHeader/index.less b/src/components/TopNavHeader/index.less deleted file mode 100644 index aad3d74e29..0000000000 --- a/src/components/TopNavHeader/index.less +++ /dev/null @@ -1,72 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.head { - position: relative; - width: 100%; - height: @layout-header-height; - box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); - transition: background 0.3s, width 0.2s; - :global { - .ant-menu-submenu.ant-menu-submenu-horizontal { - height: 100%; - line-height: @layout-header-height; - .ant-menu-submenu-title { - height: 100%; - } - } - } - &.light { - background-color: #fff; - } - .main { - display: flex; - height: @layout-header-height; - padding-left: 24px; - &.wide { - max-width: 1200px; - margin: auto; - padding-left: 0; - } - .left { - display: flex; - flex: 1; - } - .right { - width: 324px; - } - } -} - -.logo { - position: relative; - width: 165px; - height: @layout-header-height; - overflow: hidden; - line-height: @layout-header-height; - transition: all 0.3s; - img { - display: inline-block; - height: 32px; - vertical-align: middle; - } - h1 { - display: inline-block; - margin: 0 0 0 12px; - color: #fff; - font-weight: 400; - font-size: 16px; - vertical-align: top; - } -} - -.light { - h1 { - color: #002140; - } -} - -.menu { - height: @layout-header-height; - line-height: @layout-header-height; - border: none; -} diff --git a/src/components/Trend/demo/basic.md b/src/components/Trend/demo/basic.md deleted file mode 100644 index 3282914163..0000000000 --- a/src/components/Trend/demo/basic.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -order: 0 -title: 演示 ---- - -在数值背后添加一个小图标来标识涨跌情况。 - -```jsx -import Trend from 'ant-design-pro/lib/Trend'; - -ReactDOM.render( -
    - 12% - - 11% - -
    , - mountNode -); -``` diff --git a/src/components/Trend/demo/reverse.md b/src/components/Trend/demo/reverse.md deleted file mode 100644 index c22dcc572a..0000000000 --- a/src/components/Trend/demo/reverse.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -order: 0 -title: 颜色反转 ---- - -在数值背后添加一个小图标来标识涨跌情况。 - -```jsx -import Trend from 'ant-design-pro/lib/Trend'; - -ReactDOM.render( -
    - - 12% - - - 11% - -
    , - mountNode -); -``` diff --git a/src/components/Trend/index.d.ts b/src/components/Trend/index.d.ts deleted file mode 100644 index a7775ae9b5..0000000000 --- a/src/components/Trend/index.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; - -export interface ITrendProps { - colorful?: boolean; - flag: 'up' | 'down'; - style?: React.CSSProperties; - reverseColor?: boolean; - className?: string; -} - -export default class Trend extends React.Component {} diff --git a/src/components/Trend/index.js b/src/components/Trend/index.js deleted file mode 100644 index c476ef62c7..0000000000 --- a/src/components/Trend/index.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import { Icon } from 'antd'; -import classNames from 'classnames'; -import styles from './index.less'; - -const Trend = ({ colorful = true, reverseColor = false, flag, children, className, ...rest }) => { - const classString = classNames( - styles.trendItem, - { - [styles.trendItemGrey]: !colorful, - [styles.reverseColor]: reverseColor && colorful, - }, - className - ); - return ( -
    - {children} - {flag && ( - - - - )} -
    - ); -}; - -export default Trend; diff --git a/src/components/Trend/index.less b/src/components/Trend/index.less deleted file mode 100644 index 13618838af..0000000000 --- a/src/components/Trend/index.less +++ /dev/null @@ -1,37 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.trendItem { - display: inline-block; - font-size: @font-size-base; - line-height: 22px; - - .up, - .down { - position: relative; - top: 1px; - margin-left: 4px; - i { - font-size: 12px; - transform: scale(0.83); - } - } - .up { - color: @red-6; - } - .down { - top: -1px; - color: @green-6; - } - - &.trendItemGrey .up, - &.trendItemGrey .down { - color: @text-color; - } - - &.reverseColor .up { - color: @green-6; - } - &.reverseColor .down { - color: @red-6; - } -} diff --git a/src/components/Trend/index.md b/src/components/Trend/index.md deleted file mode 100644 index 0bc548668a..0000000000 --- a/src/components/Trend/index.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Trend -subtitle: 趋势标记 -cols: 1 -order: 14 ---- - -趋势符号,标记上升和下降趋势。通常用绿色代表“好”,红色代表“不好”,股票涨跌场景除外。 - -## API - -```html -50% -``` - -| 参数 | 说明 | 类型 | 默认值 | -| ------------ | ----------------------- | ------- | ------ | -| colorful | 是否彩色标记 | Boolean | true | -| flag | 上升下降标识:`up|down` | string | - | -| reverseColor | 颜色反转 | Boolean | false | diff --git a/src/components/_utils/pathTools.js b/src/components/_utils/pathTools.js deleted file mode 100644 index bfb94e74e0..0000000000 --- a/src/components/_utils/pathTools.js +++ /dev/null @@ -1,6 +0,0 @@ -// /userinfo/2144/id => ['/userinfo','/useinfo/2144,'/userindo/2144/id'] -// eslint-disable-next-line import/prefer-default-export -export function urlToList(url) { - const urllist = url.split('/').filter(i => i); - return urllist.map((urlItem, index) => `/${urllist.slice(0, index + 1).join('/')}`); -} diff --git a/src/components/_utils/pathTools.test.js b/src/components/_utils/pathTools.test.js deleted file mode 100644 index a9b9315517..0000000000 --- a/src/components/_utils/pathTools.test.js +++ /dev/null @@ -1,17 +0,0 @@ -import { urlToList } from './pathTools'; - -describe('test urlToList', () => { - it('A path', () => { - expect(urlToList('/userinfo')).toEqual(['/userinfo']); - }); - it('Secondary path', () => { - expect(urlToList('/userinfo/2144')).toEqual(['/userinfo', '/userinfo/2144']); - }); - it('Three paths', () => { - expect(urlToList('/userinfo/2144/addr')).toEqual([ - '/userinfo', - '/userinfo/2144', - '/userinfo/2144/addr', - ]); - }); -}); diff --git a/src/defaultSettings.js b/src/defaultSettings.js deleted file mode 100644 index 25887b8b88..0000000000 --- a/src/defaultSettings.js +++ /dev/null @@ -1,19 +0,0 @@ -module.exports = { - navTheme: 'dark', // theme for nav menu - primaryColor: '#1890FF', // primary color of ant design - layout: 'sidemenu', // nav menu position: sidemenu or topmenu - contentWidth: 'Fluid', // layout of content: Fluid or Fixed, only works when layout is topmenu - fixedHeader: false, // sticky header - autoHideHeader: false, // auto hide header - fixSiderbar: false, // sticky siderbar - menu: { - disableLocal: false, - }, - title: 'Ant Design Pro', - pwa: false, - // Your custom iconfont Symbol script Url - // eg://at.alicdn.com/t/font_1039637_btcrd5co4w.js - // 注意:如果需要图标多色,Iconfont 图标项目里要进行批量去色处理 - // Usage: https://github.com/ant-design/ant-design-pro/pull/3517 - iconfontUrl: '', -}; diff --git a/src/e2e/__mocks__/antd-pro-merge-less.js b/src/e2e/__mocks__/antd-pro-merge-less.js new file mode 100644 index 0000000000..f237ddf58e --- /dev/null +++ b/src/e2e/__mocks__/antd-pro-merge-less.js @@ -0,0 +1 @@ +export default undefined; diff --git a/src/e2e/baseLayout.e2e.js b/src/e2e/baseLayout.e2e.js index 70bb984df3..63f58a5a85 100644 --- a/src/e2e/baseLayout.e2e.js +++ b/src/e2e/baseLayout.e2e.js @@ -1,4 +1,6 @@ -import RouterConfig from '../../config/router.config'; +jest.mock('antd-pro-merge-less'); + +const RouterConfig = require('../../config/config').default.routes; const BASE_URL = `http://localhost:${process.env.PORT || 8000}`; @@ -22,7 +24,7 @@ describe('Homepage', () => { timeout: 2000, }); const haveFooter = await page.evaluate( - () => document.getElementsByTagName('footer').length > 0 + () => document.getElementsByTagName('footer').length > 0, ); expect(haveFooter).toBeTruthy(); }; @@ -31,7 +33,7 @@ describe('Homepage', () => { jest.setTimeout(1000000); await page.setCacheEnabled(false); }); - const routers = formatter(RouterConfig[1].routes); + const routers = formatter(RouterConfig); routers.forEach(route => { it(`test pages ${route}`, testPage(route)); }); diff --git a/src/e2e/home.e2e.js b/src/e2e/home.e2e.js deleted file mode 100644 index 0531d5f4b5..0000000000 --- a/src/e2e/home.e2e.js +++ /dev/null @@ -1,15 +0,0 @@ -const BASE_URL = `http://localhost:${process.env.PORT || 8000}`; - -describe('Homepage', () => { - beforeAll(async () => { - jest.setTimeout(1000000); - }); - it('it should have logo text', async () => { - await page.goto(BASE_URL); - await page.waitForSelector('h1', { - timeout: 5000, - }); - const text = await page.evaluate(() => document.getElementsByTagName('h1')[0].innerText); - expect(text).toContain('Ant Design Pro'); - }); -}); diff --git a/src/e2e/login.e2e.js b/src/e2e/login.e2e.js deleted file mode 100644 index b991af44ba..0000000000 --- a/src/e2e/login.e2e.js +++ /dev/null @@ -1,34 +0,0 @@ -const BASE_URL = `http://localhost:${process.env.PORT || 8000}`; - -describe('Login', () => { - beforeAll(async () => { - jest.setTimeout(1000000); - }); - - beforeEach(async () => { - await page.goto(`${BASE_URL}/user/login`, { waitUntil: 'networkidle2' }); - await page.evaluate(() => window.localStorage.setItem('antd-pro-authority', 'guest')); - }); - - it('should login with failure', async () => { - await page.waitForSelector('#userName', { - timeout: 2000, - }); - await page.type('#userName', 'mockuser'); - await page.type('#password', 'wrong_password'); - await page.click('button[type="submit"]'); - await page.waitForSelector('.ant-alert-error'); // should display error - }); - - it('should login successfully', async () => { - await page.waitForSelector('#userName', { - timeout: 2000, - }); - await page.type('#userName', 'admin'); - await page.type('#password', 'ant.design'); - await page.click('button[type="submit"]'); - await page.waitForSelector('.ant-layout-sider h1'); // should display error - const text = await page.evaluate(() => document.body.innerHTML); - expect(text).toContain('

    Ant Design Pro

    '); - }); -}); diff --git a/src/e2e/topMenu.e2e.js b/src/e2e/topMenu.e2e.js index d90983b9fe..09f2987fe7 100644 --- a/src/e2e/topMenu.e2e.js +++ b/src/e2e/topMenu.e2e.js @@ -12,7 +12,7 @@ describe('Homepage', () => { timeout: 2000, }); const haveFooter = await page.evaluate( - () => document.getElementsByTagName('footer').length > 0 + () => document.getElementsByTagName('footer').length > 0, ); expect(haveFooter).toBeTruthy(); }); diff --git a/src/e2e/userLayout.e2e.js b/src/e2e/userLayout.e2e.js deleted file mode 100644 index a2edfc7b80..0000000000 --- a/src/e2e/userLayout.e2e.js +++ /dev/null @@ -1,32 +0,0 @@ -import RouterConfig from '../../config/router.config'; - -const BASE_URL = `http://localhost:${process.env.PORT || 8000}`; - -function formatter(data) { - return data - .reduce((pre, item) => { - pre.push(item.path); - return pre; - }, []) - .filter(item => item); -} - -describe('Homepage', () => { - const testPage = path => async () => { - await page.goto(`${BASE_URL}${path}`); - await page.waitForSelector('footer', { - timeout: 2000, - }); - const haveFooter = await page.evaluate( - () => document.getElementsByTagName('footer').length > 0 - ); - expect(haveFooter).toBeTruthy(); - }; - - beforeAll(async () => { - jest.setTimeout(1000000); - }); - formatter(RouterConfig[0].routes).forEach(route => { - it(`test pages ${route}`, testPage(route)); - }); -}); diff --git a/src/global.less b/src/global.less index 1450ba46b1..dfc17df045 100644 --- a/src/global.less +++ b/src/global.less @@ -24,11 +24,6 @@ body { -moz-osx-font-smoothing: grayscale; } -.globalSpin { - width: 100%; - margin: 40px 0 !important; -} - ul, ol { list-style: none; diff --git a/src/global.js b/src/global.tsx similarity index 85% rename from src/global.js rename to src/global.tsx index 55bea308ef..3a97886280 100644 --- a/src/global.js +++ b/src/global.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { notification, Button, message } from 'antd'; import { formatMessage } from 'umi-plugin-react/locale'; -import defaultSettings from './defaultSettings'; +import defaultSettings from '../config/defaultSettings'; const { pwa } = defaultSettings; // if pwa is true @@ -12,7 +12,8 @@ if (pwa) { }); // Pop up a prompt on the page asking the user if they want to use the latest version - window.addEventListener('sw.updated', e => { + window.addEventListener('sw.updated', (event: Event) => { + const e = event as CustomEvent; const reloadSW = async () => { // Check if there is sw whose state is waiting in ServiceWorkerRegistration // https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration @@ -23,11 +24,11 @@ if (pwa) { // Send skip-waiting event to waiting SW with MessageChannel await new Promise((resolve, reject) => { const channel = new MessageChannel(); - channel.port1.onmessage = event => { - if (event.data.error) { - reject(event.data.error); + channel.port1.onmessage = msgEvent => { + if (msgEvent.data.error) { + reject(msgEvent.data.error); } else { - resolve(event.data); + resolve(msgEvent.data); } }; worker.postMessage({ type: 'skip-waiting' }, [channel.port2]); diff --git a/src/layouts/BasicLayout.js b/src/layouts/BasicLayout.js deleted file mode 100644 index 686742dd6c..0000000000 --- a/src/layouts/BasicLayout.js +++ /dev/null @@ -1,176 +0,0 @@ -import React, { Suspense } from 'react'; -import { Layout } from 'antd'; -import DocumentTitle from 'react-document-title'; -import { connect } from 'dva'; -import { ContainerQuery } from 'react-container-query'; -import classNames from 'classnames'; -import Media from 'react-media'; -import logo from '../assets/logo.svg'; -import Footer from './Footer'; -import Header from './Header'; -import Context from './MenuContext'; -import SiderMenu from '@/components/SiderMenu'; -import getPageTitle from '@/utils/getPageTitle'; -import styles from './BasicLayout.less'; - -// lazy load SettingDrawer -const SettingDrawer = React.lazy(() => import('@/components/SettingDrawer')); - -const { Content } = Layout; - -const query = { - 'screen-xs': { - maxWidth: 575, - }, - 'screen-sm': { - minWidth: 576, - maxWidth: 767, - }, - 'screen-md': { - minWidth: 768, - maxWidth: 991, - }, - 'screen-lg': { - minWidth: 992, - maxWidth: 1199, - }, - 'screen-xl': { - minWidth: 1200, - maxWidth: 1599, - }, - 'screen-xxl': { - minWidth: 1600, - }, -}; - -class BasicLayout extends React.Component { - componentDidMount() { - const { - dispatch, - route: { routes, path, authority }, - } = this.props; - dispatch({ - type: 'user/fetchCurrent', - }); - dispatch({ - type: 'setting/getSetting', - }); - dispatch({ - type: 'menu/getMenuData', - payload: { routes, path, authority }, - }); - } - - getContext() { - const { location, breadcrumbNameMap } = this.props; - return { - location, - breadcrumbNameMap, - }; - } - - getLayoutStyle = () => { - const { fixSiderbar, isMobile, collapsed, layout } = this.props; - if (fixSiderbar && layout !== 'topmenu' && !isMobile) { - return { - paddingLeft: collapsed ? '80px' : '256px', - }; - } - return null; - }; - - handleMenuCollapse = collapsed => { - const { dispatch } = this.props; - dispatch({ - type: 'global/changeLayoutCollapsed', - payload: collapsed, - }); - }; - - renderSettingDrawer = () => { - // Do not render SettingDrawer in production - // unless it is deployed in preview.pro.ant.design as demo - // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 - if ( - process.env.NODE_ENV === 'production' && - ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION !== 'site' - ) { - return null; - } - return ; - }; - - render() { - const { - navTheme, - layout: PropsLayout, - children, - location: { pathname }, - isMobile, - menuData, - breadcrumbNameMap, - fixedHeader, - } = this.props; - - const isTop = PropsLayout === 'topmenu'; - const contentStyle = !fixedHeader ? { paddingTop: 0 } : {}; - const layout = ( - - {isTop && !isMobile ? null : ( - - )} - -
    - - {children} - -
    - - - ); - return ( - - - - {params => ( - -
    {layout}
    -
    - )} -
    -
    - {this.renderSettingDrawer()} -
    - ); - } -} - -export default connect(({ global, setting, menu: menuModel }) => ({ - collapsed: global.collapsed, - layout: setting.layout, - menuData: menuModel.menuData, - breadcrumbNameMap: menuModel.breadcrumbNameMap, - ...setting, -}))(props => ( - - {isMobile => } - -)); diff --git a/src/layouts/BasicLayout.less b/src/layouts/BasicLayout.less deleted file mode 100644 index 60beb60923..0000000000 --- a/src/layouts/BasicLayout.less +++ /dev/null @@ -1,6 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.content { - margin: 24px; - padding-top: @layout-header-height; -} diff --git a/src/layouts/BasicLayout.tsx b/src/layouts/BasicLayout.tsx new file mode 100644 index 0000000000..33d94ff283 --- /dev/null +++ b/src/layouts/BasicLayout.tsx @@ -0,0 +1,103 @@ +/** + * Ant Design Pro v4 use `@ant-design/pro-layout` to handle Layout. + * You can view component api by: + * https://github.com/ant-design/ant-design-pro-layout + */ + +import { ConnectState, ConnectProps } from '@/models/connect'; +import RightContent from '@/components/GlobalHeader/RightContent'; +import { connect } from 'dva'; +import React, { useState } from 'react'; +import logo from '../assets/logo.svg'; +import Authorized from '@/utils/Authorized'; +import { formatMessage } from 'umi-plugin-react/locale'; +import { + BasicLayout as BasicLayoutComponents, + BasicLayoutProps as BasicLayoutComponentsProps, + MenuDataItem, + Settings, +} from '@ant-design/pro-layout'; +import Link from 'umi/link'; +export interface BasicLayoutProps extends BasicLayoutComponentsProps, ConnectProps { + breadcrumbNameMap: { + [path: string]: MenuDataItem; + }; + settings: Settings; +} +export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & { + breadcrumbNameMap: { + [path: string]: MenuDataItem; + }; +}; +/** + * use Authorized check all menu item + */ + +const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] => { + return menuList.map(item => { + const localItem = { ...item, children: item.children ? menuDataRender(item.children) : [] }; + return Authorized.check(item.authority, localItem, null) as MenuDataItem; + }); +}; + +const BasicLayout: React.FC = props => { + const { dispatch, children, settings } = props; + /** + * constructor + */ + + useState(() => { + if (dispatch) { + dispatch({ + type: 'user/fetchCurrent', + }); + dispatch({ + type: 'settings/getSetting', + }); + } + }); + + /** + * init variables + */ + const handleMenuCollapse = (payload: boolean) => + dispatch && + dispatch({ + type: 'global/changeLayoutCollapsed', + payload, + }); + + return ( + { + return {defaultDom}; + }} + breadcrumbRender={(routers = []) => { + return [ + { + path: '/', + breadcrumbName: formatMessage({ + id: 'menu.home', + defaultMessage: 'Home', + }), + }, + ...routers, + ]; + }} + menuDataRender={menuDataRender} + formatMessage={formatMessage} + rightContentRender={rightProps => } + {...props} + {...settings} + > + {children} + + ); +}; + +export default connect(({ global, settings }: ConnectState) => ({ + collapsed: global.collapsed, + settings, +}))(BasicLayout); diff --git a/src/layouts/BlankLayout.js b/src/layouts/BlankLayout.js deleted file mode 100644 index ef39aa4c2f..0000000000 --- a/src/layouts/BlankLayout.js +++ /dev/null @@ -1,3 +0,0 @@ -import React from 'react'; - -export default ({ children }) =>
    {children}
    ; diff --git a/src/layouts/BlankLayout.tsx b/src/layouts/BlankLayout.tsx new file mode 100644 index 0000000000..a5ff8c4cfa --- /dev/null +++ b/src/layouts/BlankLayout.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +const Layout: React.FC = ({ children }) =>
    {children}
    ; + +export default Layout; diff --git a/src/layouts/Footer.js b/src/layouts/Footer.js deleted file mode 100644 index a7775ef56e..0000000000 --- a/src/layouts/Footer.js +++ /dev/null @@ -1,37 +0,0 @@ -import React, { Fragment } from 'react'; -import { Layout, Icon } from 'antd'; -import GlobalFooter from '@/components/GlobalFooter'; - -const { Footer } = Layout; -const FooterView = () => ( -
    - , - href: 'https://github.com/ant-design/ant-design-pro', - blankTarget: true, - }, - { - key: 'Ant Design', - title: 'Ant Design', - href: 'https://ant.design', - blankTarget: true, - }, - ]} - copyright={ - - Copyright 2019 蚂蚁金服体验技术部出品 - - } - /> -
    -); -export default FooterView; diff --git a/src/layouts/Header.js b/src/layouts/Header.js deleted file mode 100644 index e58d37c56c..0000000000 --- a/src/layouts/Header.js +++ /dev/null @@ -1,163 +0,0 @@ -import React, { Component } from 'react'; -import { formatMessage } from 'umi-plugin-react/locale'; -import { Layout, message } from 'antd'; -import Animate from 'rc-animate'; -import { connect } from 'dva'; -import router from 'umi/router'; -import GlobalHeader from '@/components/GlobalHeader'; -import TopNavHeader from '@/components/TopNavHeader'; -import styles from './Header.less'; - -const { Header } = Layout; - -class HeaderView extends Component { - state = { - visible: true, - }; - - static getDerivedStateFromProps(props, state) { - if (!props.autoHideHeader && !state.visible) { - return { - visible: true, - }; - } - return null; - } - - componentDidMount() { - document.addEventListener('scroll', this.handScroll, { passive: true }); - } - - componentWillUnmount() { - document.removeEventListener('scroll', this.handScroll); - } - - getHeadWidth = () => { - const { isMobile, collapsed, setting } = this.props; - const { fixedHeader, layout } = setting; - if (isMobile || !fixedHeader || layout === 'topmenu') { - return '100%'; - } - return collapsed ? 'calc(100% - 80px)' : 'calc(100% - 256px)'; - }; - - handleNoticeClear = type => { - message.success( - `${formatMessage({ id: 'component.noticeIcon.cleared' })} ${formatMessage({ - id: `component.globalHeader.${type}`, - })}` - ); - const { dispatch } = this.props; - dispatch({ - type: 'global/clearNotices', - payload: type, - }); - }; - - handleMenuClick = ({ key }) => { - const { dispatch } = this.props; - if (key === 'userCenter') { - router.push('/account/center'); - return; - } - if (key === 'triggerError') { - router.push('/exception/trigger'); - return; - } - if (key === 'userinfo') { - router.push('/account/settings/base'); - return; - } - if (key === 'logout') { - dispatch({ - type: 'login/logout', - }); - } - }; - - handleNoticeVisibleChange = visible => { - if (visible) { - const { dispatch } = this.props; - dispatch({ - type: 'global/fetchNotices', - }); - } - }; - - handScroll = () => { - const { autoHideHeader } = this.props; - const { visible } = this.state; - if (!autoHideHeader) { - return; - } - const scrollTop = document.body.scrollTop + document.documentElement.scrollTop; - if (!this.ticking) { - this.ticking = true; - requestAnimationFrame(() => { - if (this.oldScrollTop > scrollTop) { - this.setState({ - visible: true, - }); - } else if (scrollTop > 300 && visible) { - this.setState({ - visible: false, - }); - } else if (scrollTop < 300 && !visible) { - this.setState({ - visible: true, - }); - } - this.oldScrollTop = scrollTop; - this.ticking = false; - }); - } - }; - - render() { - const { isMobile, handleMenuCollapse, setting } = this.props; - const { navTheme, layout, fixedHeader } = setting; - const { visible } = this.state; - const isTop = layout === 'topmenu'; - const width = this.getHeadWidth(); - const HeaderDom = visible ? ( -
    - {isTop && !isMobile ? ( - - ) : ( - - )} -
    - ) : null; - return ( - - {HeaderDom} - - ); - } -} - -export default connect(({ user, global, setting, loading }) => ({ - currentUser: user.currentUser, - collapsed: global.collapsed, - fetchingMoreNotices: loading.effects['global/fetchMoreNotices'], - fetchingNotices: loading.effects['global/fetchNotices'], - notices: global.notices, - setting, -}))(HeaderView); diff --git a/src/layouts/Header.less b/src/layouts/Header.less deleted file mode 100644 index cc2da96293..0000000000 --- a/src/layouts/Header.less +++ /dev/null @@ -1,8 +0,0 @@ -.fixedHeader { - position: fixed; - top: 0; - right: 0; - z-index: 9; - width: 100%; - transition: width 0.2s; -} diff --git a/src/layouts/MenuContext.js b/src/layouts/MenuContext.js deleted file mode 100644 index 860f106868..0000000000 --- a/src/layouts/MenuContext.js +++ /dev/null @@ -1,3 +0,0 @@ -import { createContext } from 'react'; - -export default createContext(); diff --git a/src/layouts/UserLayout.js b/src/layouts/UserLayout.tsx similarity index 68% rename from src/layouts/UserLayout.js rename to src/layouts/UserLayout.tsx index cb0ceadb55..df0890aaa9 100644 --- a/src/layouts/UserLayout.js +++ b/src/layouts/UserLayout.tsx @@ -1,14 +1,14 @@ -import React, { Component, Fragment } from 'react'; -import { formatMessage } from 'umi-plugin-react/locale'; -import { connect } from 'dva'; -import Link from 'umi/link'; -import { Icon } from 'antd'; +import SelectLang from '@/components/SelectLang'; import GlobalFooter from '@/components/GlobalFooter'; +import { ConnectProps } from '@/models/connect'; +import { Icon } from 'antd'; +import React, { Component, Fragment } from 'react'; import DocumentTitle from 'react-document-title'; -import SelectLang from '@/components/SelectLang'; -import styles from './UserLayout.less'; +import { formatMessage } from 'umi-plugin-locale'; +import Link from 'umi/link'; import logo from '../assets/logo.svg'; -import getPageTitle from '@/utils/getPageTitle'; +import styles from './UserLayout.less'; +import { MenuDataItem, getPageTitle, getMenuData } from '@ant-design/pro-layout'; const links = [ { @@ -34,26 +34,29 @@ const copyright = ( ); -class UserLayout extends Component { - componentDidMount() { - const { - dispatch, - route: { routes, authority }, - } = this.props; - dispatch({ - type: 'menu/getMenuData', - payload: { routes, authority }, - }); - } +export interface UserLayoutProps extends ConnectProps { + breadcrumbNameMap: { [path: string]: MenuDataItem }; + navTheme: string; +} +class UserLayout extends Component { render() { const { - children, - location: { pathname }, - breadcrumbNameMap, + route = { + routes: [], + }, } = this.props; + const { routes = [] } = route; + const { children, location } = this.props; + const { breadcrumb } = getMenuData(routes, this.props); return ( - +
    @@ -77,7 +80,4 @@ class UserLayout extends Component { } } -export default connect(({ menu: menuModel }) => ({ - menuData: menuModel.menuData, - breadcrumbNameMap: menuModel.breadcrumbNameMap, -}))(UserLayout); +export default UserLayout; diff --git a/src/locales/en-US.js b/src/locales/en-US.js deleted file mode 100644 index a10691ce54..0000000000 --- a/src/locales/en-US.js +++ /dev/null @@ -1,37 +0,0 @@ -import analysis from './en-US/analysis'; -import exception from './en-US/exception'; -import form from './en-US/form'; -import globalHeader from './en-US/globalHeader'; -import login from './en-US/login'; -import menu from './en-US/menu'; -import monitor from './en-US/monitor'; -import result from './en-US/result'; -import settingDrawer from './en-US/settingDrawer'; -import settings from './en-US/settings'; -import pwa from './en-US/pwa'; -import component from './en-US/component'; -import editor from './en-US/editor'; - -export default { - 'navBar.lang': 'Languages', - 'layout.user.link.help': 'Help', - 'layout.user.link.privacy': 'Privacy', - 'layout.user.link.terms': 'Terms', - 'app.home.introduce': 'introduce', - 'app.forms.basic.title': 'Basic form', - 'app.forms.basic.description': - 'Form pages are used to collect or verify information to users, and basic forms are common in scenarios where there are fewer data items.', - ...analysis, - ...exception, - ...form, - ...globalHeader, - ...login, - ...menu, - ...monitor, - ...result, - ...settingDrawer, - ...settings, - ...pwa, - ...component, - ...editor, -}; diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts new file mode 100644 index 0000000000..4ecc7fa7d0 --- /dev/null +++ b/src/locales/en-US.ts @@ -0,0 +1,20 @@ +import globalHeader from './en-US/globalHeader'; +import menu from './en-US/menu'; +import settingDrawer from './en-US/settingDrawer'; +import settings from './en-US/settings'; +import pwa from './en-US/pwa'; +import component from './en-US/component'; + +export default { + 'navBar.lang': 'Languages', + 'layout.user.link.help': 'Help', + 'layout.user.link.privacy': 'Privacy', + 'layout.user.link.terms': 'Terms', + 'app.preview.down.block': 'Download this page to your local project', + ...globalHeader, + ...menu, + ...settingDrawer, + ...settings, + ...pwa, + ...component, +}; diff --git a/src/locales/en-US/analysis.js b/src/locales/en-US/analysis.js deleted file mode 100644 index f3005dabda..0000000000 --- a/src/locales/en-US/analysis.js +++ /dev/null @@ -1,34 +0,0 @@ -export default { - 'app.analysis.test': 'Gongzhuan No.{no} shop', - 'app.analysis.introduce': 'Introduce', - 'app.analysis.total-sales': 'Total Sales', - 'app.analysis.day-sales': 'Daily Sales', - 'app.analysis.visits': 'Visits', - 'app.analysis.visits-trend': 'Visits Trend', - 'app.analysis.visits-ranking': 'Visits Ranking', - 'app.analysis.day-visits': 'Daily Visits', - 'app.analysis.week': 'WoW Change', - 'app.analysis.day': 'DoD Change', - 'app.analysis.payments': 'Payments', - 'app.analysis.conversion-rate': 'Conversion Rate', - 'app.analysis.operational-effect': 'Operational Effect', - 'app.analysis.sales-trend': 'Stores Sales Trend', - 'app.analysis.sales-ranking': 'Sales Ranking', - 'app.analysis.all-year': 'All Year', - 'app.analysis.all-month': 'All Month', - 'app.analysis.all-week': 'All Week', - 'app.analysis.all-day': 'All day', - 'app.analysis.search-users': 'Search Users', - 'app.analysis.per-capita-search': 'Per Capita Search', - 'app.analysis.online-top-search': 'Online Top Search', - 'app.analysis.the-proportion-of-sales': 'The Proportion Of Sales', - 'app.analysis.channel.all': 'ALL', - 'app.analysis.channel.online': 'Online', - 'app.analysis.channel.stores': 'Stores', - 'app.analysis.sales': 'Sales', - 'app.analysis.traffic': 'Traffic', - 'app.analysis.table.rank': 'Rank', - 'app.analysis.table.search-keyword': 'Keyword', - 'app.analysis.table.users': 'Users', - 'app.analysis.table.weekly-range': 'Weekly Range', -}; diff --git a/src/locales/en-US/component.js b/src/locales/en-US/component.ts similarity index 70% rename from src/locales/en-US/component.js rename to src/locales/en-US/component.ts index 910f30e111..3ba7eeda69 100644 --- a/src/locales/en-US/component.js +++ b/src/locales/en-US/component.ts @@ -2,5 +2,4 @@ export default { 'component.tagSelect.expand': 'Expand', 'component.tagSelect.collapse': 'Collapse', 'component.tagSelect.all': 'All', - 'component.miniProgress.tooltipDefault': 'Target value', }; diff --git a/src/locales/en-US/editor.js b/src/locales/en-US/editor.js deleted file mode 100644 index 81bd0f170a..0000000000 --- a/src/locales/en-US/editor.js +++ /dev/null @@ -1,11 +0,0 @@ -export default { - 'app.editor.flow.title': 'Flowchart Editor', - 'app.editor.flow.description': - 'The flow chart is an excellent way to represent the idea of the algorithm.', - 'app.editor.koni.title': 'Koni Editor', - 'app.editor.koni.description': - 'The topology diagram refers to the network structure diagram composed of network node devices and communication media.', - 'app.editor.mind.title': 'Mind Map Editor', - 'app.editor.mind.description': - 'The brain map is an effective graphical thinking tool for expressing divergent thinking. It is simple but effective and is a practical thinking tool.', -}; diff --git a/src/locales/en-US/exception.js b/src/locales/en-US/exception.js deleted file mode 100644 index 5035552afe..0000000000 --- a/src/locales/en-US/exception.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - 'app.exception.back': 'Back to home', - 'app.exception.description.403': "Sorry, you don't have access to this page", - 'app.exception.description.404': 'Sorry, the page you visited does not exist', - 'app.exception.description.500': 'Sorry, the server is reporting an error', -}; diff --git a/src/locales/en-US/form.js b/src/locales/en-US/form.js deleted file mode 100644 index 36e088d3e4..0000000000 --- a/src/locales/en-US/form.js +++ /dev/null @@ -1,38 +0,0 @@ -export default { - 'form.get-captcha': 'Get Captcha', - 'form.captcha.second': 'sec', - 'form.optional': ' (optional) ', - 'form.submit': 'Submit', - 'form.save': 'Save', - 'form.email.placeholder': 'Email', - 'form.password.placeholder': 'Password', - 'form.confirm-password.placeholder': 'Confirm password', - 'form.phone-number.placeholder': 'Phone number', - 'form.verification-code.placeholder': 'Verification code', - 'form.title.label': 'Title', - 'form.title.placeholder': 'Give the target a name', - 'form.date.label': 'Start and end date', - 'form.date.placeholder.start': 'Start date', - 'form.date.placeholder.end': 'End date', - 'form.goal.label': 'Goal description', - 'form.goal.placeholder': 'Please enter your work goals', - 'form.standard.label': 'Metrics', - 'form.standard.placeholder': 'Please enter a metric', - 'form.client.label': 'Client', - 'form.client.label.tooltip': 'Target service object', - 'form.client.placeholder': - 'Please describe your customer service, internal customers directly @ Name / job number', - 'form.invites.label': 'Inviting critics', - 'form.invites.placeholder': 'Please direct @ Name / job number, you can invite up to 5 people', - 'form.weight.label': 'Weight', - 'form.weight.placeholder': 'Please enter weight', - 'form.public.label': 'Target disclosure', - 'form.public.label.help': 'Customers and invitees are shared by default', - 'form.public.radio.public': 'Public', - 'form.public.radio.partially-public': 'Partially public', - 'form.public.radio.private': 'Private', - 'form.publicUsers.placeholder': 'Open to', - 'form.publicUsers.option.A': 'Colleague A', - 'form.publicUsers.option.B': 'Colleague B', - 'form.publicUsers.option.C': 'Colleague C', -}; diff --git a/src/locales/en-US/globalHeader.js b/src/locales/en-US/globalHeader.ts similarity index 100% rename from src/locales/en-US/globalHeader.js rename to src/locales/en-US/globalHeader.ts diff --git a/src/locales/en-US/login.js b/src/locales/en-US/login.js deleted file mode 100644 index 195e59ce32..0000000000 --- a/src/locales/en-US/login.js +++ /dev/null @@ -1,41 +0,0 @@ -export default { - 'app.login.userName': 'userName', - 'app.login.password': 'password', - 'app.login.message-invalid-credentials': 'Invalid username or password(admin/ant.design)', - 'app.login.message-invalid-verification-code': 'Invalid verification code', - 'app.login.tab-login-credentials': 'Credentials', - 'app.login.tab-login-mobile': 'Mobile number', - 'app.login.remember-me': 'Remember me', - 'app.login.forgot-password': 'Forgot your password?', - 'app.login.sign-in-with': 'Sign in with', - 'app.login.signup': 'Sign up', - 'app.login.login': 'Login', - 'app.register.register': 'Register', - 'app.register.get-verification-code': 'Get code', - 'app.login.verification-code-warning': - 'This project is a demo project and will not actually send you a verification code. Please switch to the account password login interface and log in as prompted.', - 'app.register.sign-in': 'Already have an account?', - 'app.register-result.msg': 'Account:registered at {email}', - 'app.register-result.activation-email': - 'The activation email has been sent to your email address and is valid for 24 hours. Please log in to the email in time and click on the link in the email to activate the account.', - 'app.register-result.back-home': 'Back to home', - 'app.register-result.view-mailbox': 'View mailbox', - 'validation.email.required': 'Please enter your email!', - 'validation.email.wrong-format': 'The email address is in the wrong format!', - 'validation.userName.required': 'Please enter your userName!', - 'validation.password.required': 'Please enter your password!', - 'validation.password.twice': 'The passwords entered twice do not match!', - 'validation.password.strength.msg': - "Please enter at least 6 characters and don't use passwords that are easy to guess.", - 'validation.password.strength.strong': 'Strength: strong', - 'validation.password.strength.medium': 'Strength: medium', - 'validation.password.strength.short': 'Strength: too short', - 'validation.confirm-password.required': 'Please confirm your password!', - 'validation.phone-number.required': 'Please enter your phone number!', - 'validation.phone-number.wrong-format': 'Malformed phone number!', - 'validation.verification-code.required': 'Please enter the verification code!', - 'validation.title.required': 'Please enter a title', - 'validation.date.required': 'Please select the start and end date', - 'validation.goal.required': 'Please enter a description of the goal', - 'validation.standard.required': 'Please enter a metric', -}; diff --git a/src/locales/en-US/menu.js b/src/locales/en-US/menu.ts similarity index 56% rename from src/locales/en-US/menu.js rename to src/locales/en-US/menu.ts index 25805ead5e..8e0026fe3a 100644 --- a/src/locales/en-US/menu.js +++ b/src/locales/en-US/menu.ts @@ -1,4 +1,6 @@ export default { + 'menu.welcome': 'Welcome', + 'menu.more-blocks': 'More Blocks', 'menu.home': 'Home', 'menu.login': 'Login', 'menu.register': 'Register', @@ -7,21 +9,24 @@ export default { 'menu.dashboard.analysis': 'Analysis', 'menu.dashboard.monitor': 'Monitor', 'menu.dashboard.workplace': 'Workplace', + 'menu.exception.403': '403', + 'menu.exception.404': '404', + 'menu.exception.500': '500', 'menu.form': 'Form', - 'menu.form.basicform': 'Basic Form', - 'menu.form.stepform': 'Step Form', - 'menu.form.stepform.info': 'Step Form(write transfer information)', - 'menu.form.stepform.confirm': 'Step Form(confirm transfer information)', - 'menu.form.stepform.result': 'Step Form(finished)', - 'menu.form.advancedform': 'Advanced Form', + 'menu.form.basic-form': 'Basic Form', + 'menu.form.step-form': 'Step Form', + 'menu.form.step-form.info': 'Step Form(write transfer information)', + 'menu.form.step-form.confirm': 'Step Form(confirm transfer information)', + 'menu.form.step-form.result': 'Step Form(finished)', + 'menu.form.advanced-form': 'Advanced Form', 'menu.list': 'List', - 'menu.list.searchtable': 'Search Table', - 'menu.list.basiclist': 'Basic List', - 'menu.list.cardlist': 'Card List', - 'menu.list.searchlist': 'Search List', - 'menu.list.searchlist.articles': 'Search List(articles)', - 'menu.list.searchlist.projects': 'Search List(projects)', - 'menu.list.searchlist.applications': 'Search List(applications)', + 'menu.list.table-list': 'Search Table', + 'menu.list.basic-list': 'Basic List', + 'menu.list.card-list': 'Card List', + 'menu.list.search-list': 'Search List', + 'menu.list.search-list.articles': 'Search List(articles)', + 'menu.list.search-list.projects': 'Search List(projects)', + 'menu.list.search-list.applications': 'Search List(applications)', 'menu.profile': 'Profile', 'menu.profile.basic': 'Basic Profile', 'menu.profile.advanced': 'Advanced Profile', diff --git a/src/locales/en-US/monitor.js b/src/locales/en-US/monitor.js deleted file mode 100644 index dcb570552f..0000000000 --- a/src/locales/en-US/monitor.js +++ /dev/null @@ -1,18 +0,0 @@ -export default { - 'app.monitor.trading-activity': 'Real-Time Trading Activity', - 'app.monitor.total-transactions': 'Total transactions today', - 'app.monitor.sales-target': 'Sales target completion rate', - 'app.monitor.remaining-time': 'Remaining time of activity', - 'app.monitor.total-transactions-per-second': 'Total transactions per second', - 'app.monitor.activity-forecast': 'Activity forecast', - 'app.monitor.efficiency': 'Efficiency', - 'app.monitor.ratio': 'Ratio', - 'app.monitor.proportion-per-category': 'Proportion Per Category', - 'app.monitor.fast-food': 'Fast food', - 'app.monitor.western-food': 'Western food', - 'app.monitor.hot-pot': 'Hot pot', - 'app.monitor.waiting-for-implementation': 'Waiting for implementation', - 'app.monitor.popular-searches': 'Popular Searches', - 'app.monitor.resource-surplus': 'Resource Surplus', - 'app.monitor.fund-surplus': 'Fund Surplus', -}; diff --git a/src/locales/en-US/pwa.js b/src/locales/en-US/pwa.ts similarity index 100% rename from src/locales/en-US/pwa.js rename to src/locales/en-US/pwa.ts diff --git a/src/locales/en-US/result.js b/src/locales/en-US/result.js deleted file mode 100644 index 23de8b7b7a..0000000000 --- a/src/locales/en-US/result.js +++ /dev/null @@ -1,28 +0,0 @@ -export default { - 'app.result.error.title': 'Submission Failed', - 'app.result.error.description': - 'Please check and modify the following information before resubmitting.', - 'app.result.error.hint-title': 'The content you submitted has the following error:', - 'app.result.error.hint-text1': 'Your account has been frozen', - 'app.result.error.hint-btn1': 'Thaw immediately', - 'app.result.error.hint-text2': 'Your account is not yet eligible to apply', - 'app.result.error.hint-btn2': 'Upgrade immediately', - 'app.result.error.btn-text': 'Return to modify', - 'app.result.success.title': 'Submission Success', - 'app.result.success.description': - 'The submission results page is used to feed back the results of a series of operational tasks. If it is a simple operation, use the Message global prompt feedback. This text area can show a simple supplementary explanation. If there is a similar requirement for displaying “documents”, the following gray area can present more complicated content.', - 'app.result.success.operate-title': 'Project Name', - 'app.result.success.operate-id': 'Project ID:', - 'app.result.success.principal': 'Principal:', - 'app.result.success.operate-time': 'Effective time:', - 'app.result.success.step1-title': 'Create project', - 'app.result.success.step1-operator': 'Qu Lili', - 'app.result.success.step2-title': 'Departmental preliminary review', - 'app.result.success.step2-operator': 'Zhou Maomao', - 'app.result.success.step2-extra': 'Urge', - 'app.result.success.step3-title': 'Financial review', - 'app.result.success.step4-title': 'Finish', - 'app.result.success.btn-return': 'Back to list', - 'app.result.success.btn-project': 'View project', - 'app.result.success.btn-print': 'Print', -}; diff --git a/src/locales/en-US/settingDrawer.js b/src/locales/en-US/settingDrawer.ts similarity index 100% rename from src/locales/en-US/settingDrawer.js rename to src/locales/en-US/settingDrawer.ts diff --git a/src/locales/en-US/settings.js b/src/locales/en-US/settings.ts similarity index 100% rename from src/locales/en-US/settings.js rename to src/locales/en-US/settings.ts diff --git a/src/locales/pt-BR.js b/src/locales/pt-BR.js deleted file mode 100644 index 19e82643d4..0000000000 --- a/src/locales/pt-BR.js +++ /dev/null @@ -1,37 +0,0 @@ -import analysis from './pt-BR/analysis'; -import exception from './pt-BR/exception'; -import form from './pt-BR/form'; -import globalHeader from './pt-BR/globalHeader'; -import login from './pt-BR/login'; -import menu from './pt-BR/menu'; -import monitor from './pt-BR/monitor'; -import result from './pt-BR/result'; -import settingDrawer from './pt-BR/settingDrawer'; -import settings from './pt-BR/settings'; -import pwa from './pt-BR/pwa'; -import component from './pt-BR/component'; -import editor from './pt-BR/editor'; - -export default { - 'navBar.lang': 'Idiomas', - 'layout.user.link.help': 'ajuda', - 'layout.user.link.privacy': 'política de privacidade', - 'layout.user.link.terms': 'termos de serviços', - 'app.home.introduce': 'introduzir', - 'app.forms.basic.title': 'Basic form', - 'app.forms.basic.description': - 'Páginas de formulário são usadas para coletar e verificar as informações dos usuários e formulários básicos são comuns nos cenários onde existem alguns formatos de informações.', - ...analysis, - ...exception, - ...form, - ...globalHeader, - ...login, - ...menu, - ...monitor, - ...result, - ...settingDrawer, - ...settings, - ...pwa, - ...component, - ...editor, -}; diff --git a/src/locales/pt-BR.ts b/src/locales/pt-BR.ts new file mode 100644 index 0000000000..3ba8ef133c --- /dev/null +++ b/src/locales/pt-BR.ts @@ -0,0 +1,20 @@ +import globalHeader from './pt-BR/globalHeader'; +import menu from './pt-BR/menu'; +import settingDrawer from './pt-BR/settingDrawer'; +import settings from './pt-BR/settings'; +import pwa from './pt-BR/pwa'; +import component from './pt-BR/component'; + +export default { + 'navBar.lang': 'Idiomas', + 'layout.user.link.help': 'ajuda', + 'layout.user.link.privacy': 'política de privacidade', + 'layout.user.link.terms': 'termos de serviços', + 'app.preview.down.block': 'Download this page to your local project', + ...globalHeader, + ...menu, + ...settingDrawer, + ...settings, + ...pwa, + ...component, +}; diff --git a/src/locales/pt-BR/analysis.js b/src/locales/pt-BR/analysis.js deleted file mode 100644 index eb33f10b65..0000000000 --- a/src/locales/pt-BR/analysis.js +++ /dev/null @@ -1,34 +0,0 @@ -export default { - 'app.analysis.test': 'Gongzhuan No.{no} shop', - 'app.analysis.introduce': 'Introduzir', - 'app.analysis.total-sales': 'Vendas Totais', - 'app.analysis.day-sales': 'Vendas do Dia', - 'app.analysis.visits': 'Visitas', - 'app.analysis.visits-trend': 'Tendência de Visitas', - 'app.analysis.visits-ranking': 'Ranking de Visitas', - 'app.analysis.day-visits': 'Visitas do Dia', - 'app.analysis.week': 'Taxa Semanal', - 'app.analysis.day': 'Taxa Diária', - 'app.analysis.payments': 'Pagamentos', - 'app.analysis.conversion-rate': 'Taxa de Conversão', - 'app.analysis.operational-effect': 'Efeito Operacional', - 'app.analysis.sales-trend': 'Tendência de Vendas das Lojas', - 'app.analysis.sales-ranking': 'Ranking de Vendas', - 'app.analysis.all-year': 'Todo ano', - 'app.analysis.all-month': 'Todo mês', - 'app.analysis.all-week': 'Toda semana', - 'app.analysis.all-day': 'Todo dia', - 'app.analysis.search-users': 'Pesquisa de Usuários', - 'app.analysis.per-capita-search': 'Busca Per Capta', - 'app.analysis.online-top-search': 'Mais Buscadas Online', - 'app.analysis.the-proportion-of-sales': 'Proporção de Vendas', - 'app.analysis.channel.all': 'Tudo', - 'app.analysis.channel.online': 'Online', - 'app.analysis.channel.stores': 'Lojas', - 'app.analysis.sales': 'Vendas', - 'app.analysis.traffic': 'Tráfego', - 'app.analysis.table.rank': 'Rank', - 'app.analysis.table.search-keyword': 'Palavra chave', - 'app.analysis.table.users': 'Usuários', - 'app.analysis.table.weekly-range': 'Faixa Semanal', -}; diff --git a/src/locales/pt-BR/component.js b/src/locales/pt-BR/component.ts similarity index 72% rename from src/locales/pt-BR/component.js rename to src/locales/pt-BR/component.ts index d3a2c1b313..7cf9999c3a 100644 --- a/src/locales/pt-BR/component.js +++ b/src/locales/pt-BR/component.ts @@ -2,5 +2,4 @@ export default { 'component.tagSelect.expand': 'Expandir', 'component.tagSelect.collapse': 'Diminuir', 'component.tagSelect.all': 'Todas', - 'component.miniProgress.tooltipDefault': 'Valor alvo', }; diff --git a/src/locales/pt-BR/editor.js b/src/locales/pt-BR/editor.js deleted file mode 100644 index 10237f9b74..0000000000 --- a/src/locales/pt-BR/editor.js +++ /dev/null @@ -1,11 +0,0 @@ -export default { - 'app.editor.flow.title': 'Editor de diagrama de flujo', - 'app.editor.flow.description': - 'El diagrama de flujo es una excelente manera de representar la idea del algoritmo.', - 'app.editor.koni.title': 'Editor de topologia', - 'app.editor.koni.description': - 'El diagrama de topología se refiere al diagrama de estructura de red compuesto por dispositivos de nodo de red y medios de comunicación.', - 'app.editor.mind.title': 'Editor de mapas cerebrales', - 'app.editor.mind.description': - 'El mapa cerebral es una herramienta de pensamiento gráfico eficaz para expresar el pensamiento divergente. Es simple pero efectivo y es una herramienta de pensamiento práctico.', -}; diff --git a/src/locales/pt-BR/exception.js b/src/locales/pt-BR/exception.js deleted file mode 100644 index ff4f1a8dd9..0000000000 --- a/src/locales/pt-BR/exception.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - 'app.exception.back': 'Voltar para Início', - 'app.exception.description.403': 'Desculpe, você não tem acesso a esta página', - 'app.exception.description.404': 'Desculpe, a página que você visitou não existe', - 'app.exception.description.500': 'Desculpe, o servidor está reportando um erro', -}; diff --git a/src/locales/pt-BR/form.js b/src/locales/pt-BR/form.js deleted file mode 100644 index 8e5b76022d..0000000000 --- a/src/locales/pt-BR/form.js +++ /dev/null @@ -1,39 +0,0 @@ -export default { - 'form.get-captcha': 'Get Captcha', - 'form.captcha.second': 'sec', - 'form.email.placeholder': 'Email', - 'form.password.placeholder': 'Senha', - 'form.confirm-password.placeholder': 'Confirme a senha', - 'form.phone-number.placeholder': 'Telefone', - 'form.verification-code.placeholder': 'Código de verificação', - 'form.optional': ' (opcional) ', - 'form.submit': 'Enviar', - 'form.save': 'Salvar', - 'form.title.label': 'Titulo', - 'form.title.placeholder': 'Dê o nome do input', - 'form.date.label': 'Período', - 'form.date.placeholder.start': 'Data Inicial', - 'form.date.placeholder.end': 'Data Final', - 'form.goal.label': 'Objetivos', - 'form.goal.placeholder': 'Por favor, digite os seus objetivos', - 'form.standard.label': 'Métricas', - 'form.standard.placeholder': 'Por favor, digite suas métricas', - 'form.client.label': 'Cliente', - 'form.client.label.tooltip': 'Target service object', - 'form.client.placeholder': - 'Por favor, descreva seu atendimento ao cliente, clientes internos diretamente @ Nome / número do trabalho', - 'form.invites.label': 'Convidados críticos', - 'form.invites.placeholder': - 'Por favor, dirija @ Nome / número do trabalho, você pode convidar até 5 pessoas', - 'form.weight.label': 'Peso', - 'form.weight.placeholder': 'Por favor, entre com o peso', - 'form.public.label': 'Revelação de objetivo', - 'form.public.label.help': 'Clientes e convidados são compartilhados por padrão', - 'form.public.radio.public': 'Publico', - 'form.public.radio.partially-public': 'Parcialmente publico', - 'form.public.radio.private': 'Privado', - 'form.publicUsers.placeholder': 'Aberto para', - 'form.publicUsers.option.A': 'Colega A', - 'form.publicUsers.option.B': 'Colega B', - 'form.publicUsers.option.C': 'Colega C', -}; diff --git a/src/locales/pt-BR/globalHeader.js b/src/locales/pt-BR/globalHeader.ts similarity index 100% rename from src/locales/pt-BR/globalHeader.js rename to src/locales/pt-BR/globalHeader.ts diff --git a/src/locales/pt-BR/login.js b/src/locales/pt-BR/login.js deleted file mode 100644 index 5e2d86954a..0000000000 --- a/src/locales/pt-BR/login.js +++ /dev/null @@ -1,38 +0,0 @@ -export default { - 'app.login.userName': 'Nome de usuário', - 'app.login.password': 'Sua senha', - 'app.login.message-invalid-credentials': - 'Nome de usuário ou senha inválidosd(admin/ant.design)', - 'app.login.message-invalid-verification-code': 'Código de verificação inválido', - 'app.login.tab-login-credentials': 'Credenciais', - 'app.login.tab-login-mobile': 'Telefone', - 'app.login.remember-me': 'Lembre-me', - 'app.login.forgot-password': 'Esqueceu sua senha?', - 'app.login.sign-in-with': 'Login com', - 'app.login.signup': 'Cadastre-se', - 'app.login.login': 'Login', - 'app.register.register': 'Cadastro', - 'app.register.get-verification-code': 'Recuperar código', - 'app.login.verification-code-warning': - 'This project is a demo project and will not actually send you a verification code. Please switch to the account password login interface and log in as prompted.', - 'app.register.sign-in': 'Já tem uma conta?', - 'app.register-result.msg': 'Conta:registrada em {email}', - 'app.register-result.activation-email': - 'Um email de ativação foi enviado para o seu email e é válido por 24 horas. Por favor entre no seu email e clique no link de ativação da conta.', - 'app.register-result.back-home': 'Voltar ao Início', - 'app.register-result.view-mailbox': 'Visualizar a caixa de email', - 'validation.email.required': 'Por favor insira seu email!', - 'validation.email.wrong-format': 'O email está errado!', - 'validation.userName.required': 'Por favor insira nome de usuário!', - 'validation.password.required': 'Por favor insira sua senha!', - 'validation.password.twice': 'As senhas não estão iguais!', - 'validation.password.strength.msg': - 'Por favor insira pelo menos 6 caracteres e não use senhas fáceis de adivinhar.', - 'validation.password.strength.strong': 'Força: forte', - 'validation.password.strength.medium': 'Força: média', - 'validation.password.strength.short': 'Força: curta', - 'validation.confirm-password.required': 'Por favor confirme sua senha!', - 'validation.phone-number.required': 'Por favor insira seu telefone!', - 'validation.phone-number.wrong-format': 'Formato de telefone errado!', - 'validation.verification-code.required': 'Por favor insira seu código de verificação!', -}; diff --git a/src/locales/pt-BR/menu.js b/src/locales/pt-BR/menu.ts similarity index 54% rename from src/locales/pt-BR/menu.js rename to src/locales/pt-BR/menu.ts index 994f73cd10..3666b6b665 100644 --- a/src/locales/pt-BR/menu.js +++ b/src/locales/pt-BR/menu.ts @@ -1,4 +1,7 @@ export default { + 'menu.welcome': 'Welcome', + 'menu.more-blocks': 'More Blocks', + 'menu.home': 'Início', 'menu.login': 'Login', 'menu.register': 'Registro', @@ -7,21 +10,24 @@ export default { 'menu.dashboard.analysis': 'Análise', 'menu.dashboard.monitor': 'Monitor', 'menu.dashboard.workplace': 'Ambiente de Trabalho', + 'menu.exception.403': '403', + 'menu.exception.404': '404', + 'menu.exception.500': '500', 'menu.form': 'Formulário', - 'menu.form.basicform': 'Formulário Básico', - 'menu.form.stepform': 'Formulário Assistido', - 'menu.form.stepform.info': 'Formulário Assistido(gravar informações de transferência)', - 'menu.form.stepform.confirm': 'Formulário Assistido(confirmar informações de transferência)', - 'menu.form.stepform.result': 'Formulário Assistido(finalizado)', - 'menu.form.advancedform': 'Formulário Avançado', + 'menu.form.basic-form': 'Formulário Básico', + 'menu.form.step-form': 'Formulário Assistido', + 'menu.form.step-form.info': 'Formulário Assistido(gravar informações de transferência)', + 'menu.form.step-form.confirm': 'Formulário Assistido(confirmar informações de transferência)', + 'menu.form.step-form.result': 'Formulário Assistido(finalizado)', + 'menu.form.advanced-form': 'Formulário Avançado', 'menu.list': 'Lista', - 'menu.list.searchtable': 'Tabela de Busca', - 'menu.list.basiclist': 'Lista Básica', - 'menu.list.cardlist': 'Lista de Card', - 'menu.list.searchlist': 'Lista de Busca', - 'menu.list.searchlist.articles': 'Lista de Busca(artigos)', - 'menu.list.searchlist.projects': 'Lista de Busca(projetos)', - 'menu.list.searchlist.applications': 'Lista de Busca(aplicações)', + 'menu.list.table-list': 'Tabela de Busca', + 'menu.list.basic-list': 'Lista Básica', + 'menu.list.card-list': 'Lista de Card', + 'menu.list.search-list': 'Lista de Busca', + 'menu.list.search-list.articles': 'Lista de Busca(artigos)', + 'menu.list.search-list.projects': 'Lista de Busca(projetos)', + 'menu.list.search-list.applications': 'Lista de Busca(aplicações)', 'menu.profile': 'Perfil', 'menu.profile.basic': 'Perfil Básico', 'menu.profile.advanced': 'Perfil Avançado', diff --git a/src/locales/pt-BR/monitor.js b/src/locales/pt-BR/monitor.js deleted file mode 100644 index 44a260843e..0000000000 --- a/src/locales/pt-BR/monitor.js +++ /dev/null @@ -1,19 +0,0 @@ -export default { - 'app.monitor.trading-activity': 'Atividade de Trading Real-time', - 'app.monitor.total-transactions': 'Total de transações hoje', - 'app.monitor.sales-target': 'Taxa de conclusão da meta de vendas', - 'app.monitor.remaining-time': 'Tempo restante da atividade', - 'app.monitor.total-transactions-per-second': 'Total de transações por segundo', - 'app.monitor.activity-forecast': 'Previsão atual', - 'app.monitor.efficiency': 'Eficiência', - 'app.monitor.ratio': 'Relação', - 'app.monitor.proportion-per-category': 'Proporção por categoria', - 'app.monitor.fast-food': 'Fast food', - 'app.monitor.western-food': 'Comida Ocidental', - 'app.monitor.hot-pot': 'Hot pot', - 'app.monitor.waiting-for-implementation': 'Aguardando implementação', - 'app.monitor.popular-searches': 'Buscas populares', - 'app.monitor.resource-surplus': 'Excedente de recursos', - 'app.monitor.fund-surplus': 'Excedente do fundo', - 'app.exception.back': 'Voltar a home', -}; diff --git a/src/locales/pt-BR/pwa.js b/src/locales/pt-BR/pwa.ts similarity index 100% rename from src/locales/pt-BR/pwa.js rename to src/locales/pt-BR/pwa.ts diff --git a/src/locales/pt-BR/result.js b/src/locales/pt-BR/result.js deleted file mode 100644 index 2720e07221..0000000000 --- a/src/locales/pt-BR/result.js +++ /dev/null @@ -1,28 +0,0 @@ -export default { - 'app.result.error.title': 'A Submissão Falhou', - 'app.result.error.description': - 'Por favor, verifique e modifique as seguintes informações antes de reenviar.', - 'app.result.error.hint-title': 'O conteúdo que você enviou tem o seguinte erro:', - 'app.result.error.hint-text1': 'Sua conta foi congelada', - 'app.result.error.hint-btn1': 'Descongele imediatamente', - 'app.result.error.hint-text2': 'Sua conta ainda não está qualificada para se candidatar', - 'app.result.error.hint-btn2': 'Atualizar imediatamente', - 'app.result.error.btn-text': 'Retornar para modificar', - 'app.result.success.title': 'A Submissão foi um Sucesso', - 'app.result.success.description': - 'A página de resultados de envio é usada para fornecer os resultados de uma série de tarefas operacionais. Se for uma operação simples, use o prompt de feedback de Mensagem global. Esta área de texto pode mostrar uma explicação suplementar simples. Se houver um requisito semelhante para exibir "documentos", a área cinza a seguir pode apresentar um conteúdo mais complicado.', - 'app.result.success.operate-title': 'Nome do Projeto', - 'app.result.success.operate-id': 'ID do Projeto:', - 'app.result.success.principal': 'Principal:', - 'app.result.success.operate-time': 'Tempo efetivo:', - 'app.result.success.step1-title': 'Criar projeto', - 'app.result.success.step1-operator': 'Qu Lili', - 'app.result.success.step2-title': 'Revisão preliminar do departamento', - 'app.result.success.step2-operator': 'Zhou Maomao', - 'app.result.success.step2-extra': 'Urge', - 'app.result.success.step3-title': 'Revisão financeira', - 'app.result.success.step4-title': 'Terminar', - 'app.result.success.btn-return': 'Voltar a lista', - 'app.result.success.btn-project': 'Ver projeto', - 'app.result.success.btn-print': 'imprimir', -}; diff --git a/src/locales/pt-BR/settingDrawer.js b/src/locales/pt-BR/settingDrawer.ts similarity index 100% rename from src/locales/pt-BR/settingDrawer.js rename to src/locales/pt-BR/settingDrawer.ts diff --git a/src/locales/pt-BR/settings.js b/src/locales/pt-BR/settings.ts similarity index 100% rename from src/locales/pt-BR/settings.js rename to src/locales/pt-BR/settings.ts diff --git a/src/locales/zh-CN.js b/src/locales/zh-CN.js deleted file mode 100644 index 6cc85e4b9a..0000000000 --- a/src/locales/zh-CN.js +++ /dev/null @@ -1,37 +0,0 @@ -import analysis from './zh-CN/analysis'; -import exception from './zh-CN/exception'; -import form from './zh-CN/form'; -import globalHeader from './zh-CN/globalHeader'; -import login from './zh-CN/login'; -import menu from './zh-CN/menu'; -import monitor from './zh-CN/monitor'; -import result from './zh-CN/result'; -import settingDrawer from './zh-CN/settingDrawer'; -import settings from './zh-CN/settings'; -import pwa from './zh-CN/pwa'; -import component from './zh-CN/component'; -import editor from './zh-CN/editor'; - -export default { - 'navBar.lang': '语言', - 'layout.user.link.help': '帮助', - 'layout.user.link.privacy': '隐私', - 'layout.user.link.terms': '条款', - 'app.home.introduce': '介绍', - 'app.forms.basic.title': '基础表单', - 'app.forms.basic.description': - '表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。', - ...analysis, - ...exception, - ...form, - ...globalHeader, - ...login, - ...menu, - ...monitor, - ...result, - ...settingDrawer, - ...settings, - ...pwa, - ...component, - ...editor, -}; diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts new file mode 100644 index 0000000000..ec02f5e31e --- /dev/null +++ b/src/locales/zh-CN.ts @@ -0,0 +1,20 @@ +import globalHeader from './zh-CN/globalHeader'; +import menu from './zh-CN/menu'; +import settingDrawer from './zh-CN/settingDrawer'; +import settings from './zh-CN/settings'; +import pwa from './zh-CN/pwa'; +import component from './zh-CN/component'; + +export default { + 'navBar.lang': '语言', + 'layout.user.link.help': '帮助', + 'layout.user.link.privacy': '隐私', + 'layout.user.link.terms': '条款', + 'app.preview.down.block': '下载此页面到本地项目', + ...globalHeader, + ...menu, + ...settingDrawer, + ...settings, + ...pwa, + ...component, +}; diff --git a/src/locales/zh-CN/analysis.js b/src/locales/zh-CN/analysis.js deleted file mode 100644 index 8ed17ed830..0000000000 --- a/src/locales/zh-CN/analysis.js +++ /dev/null @@ -1,34 +0,0 @@ -export default { - 'app.analysis.test': '工专路 {no} 号店', - 'app.analysis.introduce': '指标说明', - 'app.analysis.total-sales': '总销售额', - 'app.analysis.day-sales': '日销售额', - 'app.analysis.visits': '访问量', - 'app.analysis.visits-trend': '访问量趋势', - 'app.analysis.visits-ranking': '门店访问量排名', - 'app.analysis.day-visits': '日访问量', - 'app.analysis.week': '周同比', - 'app.analysis.day': '日同比', - 'app.analysis.payments': '支付笔数', - 'app.analysis.conversion-rate': '转化率', - 'app.analysis.operational-effect': '运营活动效果', - 'app.analysis.sales-trend': '销售趋势', - 'app.analysis.sales-ranking': '门店销售额排名', - 'app.analysis.all-year': '全年', - 'app.analysis.all-month': '本月', - 'app.analysis.all-week': '本周', - 'app.analysis.all-day': '今日', - 'app.analysis.search-users': '搜索用户数', - 'app.analysis.per-capita-search': '人均搜索次数', - 'app.analysis.online-top-search': '线上热门搜索', - 'app.analysis.the-proportion-of-sales': '销售额类别占比', - 'app.analysis.channel.all': '全部渠道', - 'app.analysis.channel.online': '线上', - 'app.analysis.channel.stores': '门店', - 'app.analysis.sales': '销售额', - 'app.analysis.traffic': '客流量', - 'app.analysis.table.rank': '排名', - 'app.analysis.table.search-keyword': '搜索关键词', - 'app.analysis.table.users': '用户数', - 'app.analysis.table.weekly-range': '周涨幅', -}; diff --git a/src/locales/zh-CN/component.js b/src/locales/zh-CN/component.ts similarity index 72% rename from src/locales/zh-CN/component.js rename to src/locales/zh-CN/component.ts index 8d988ca0be..1f1feadbf6 100644 --- a/src/locales/zh-CN/component.js +++ b/src/locales/zh-CN/component.ts @@ -2,5 +2,4 @@ export default { 'component.tagSelect.expand': '展开', 'component.tagSelect.collapse': '收起', 'component.tagSelect.all': '全部', - 'component.miniProgress.tooltipDefault': '目标值', }; diff --git a/src/locales/zh-CN/editor.js b/src/locales/zh-CN/editor.js deleted file mode 100644 index 1688644e81..0000000000 --- a/src/locales/zh-CN/editor.js +++ /dev/null @@ -1,9 +0,0 @@ -export default { - 'app.editor.flow.title': '流程图编辑器', - 'app.editor.flow.description': '千言万语不如一张图,流程图是表示算法思路的好方法', - 'app.editor.koni.title': '拓扑编辑器', - 'app.editor.koni.description': '拓扑结构图是指由网络节点设备和通信介质构成的网络结构图', - 'app.editor.mind.title': '脑图编辑器', - 'app.editor.mind.description': - '脑图是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。', -}; diff --git a/src/locales/zh-CN/exception.js b/src/locales/zh-CN/exception.js deleted file mode 100644 index 1b89ab76b3..0000000000 --- a/src/locales/zh-CN/exception.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - 'app.exception.back': '返回首页', - 'app.exception.description.403': '抱歉,你无权访问此页面', - 'app.exception.description.404': '抱歉,你访问的页面不存在', - 'app.exception.description.500': '抱歉,服务器出错了', -}; diff --git a/src/locales/zh-CN/form.js b/src/locales/zh-CN/form.js deleted file mode 100644 index 7f3bd95250..0000000000 --- a/src/locales/zh-CN/form.js +++ /dev/null @@ -1,37 +0,0 @@ -export default { - 'form.get-captcha': '获取验证码', - 'form.captcha.second': '秒', - 'form.optional': '(选填)', - 'form.submit': '提交', - 'form.save': '保存', - 'form.email.placeholder': '邮箱', - 'form.password.placeholder': '至少6位密码,区分大小写', - 'form.confirm-password.placeholder': '确认密码', - 'form.phone-number.placeholder': '手机号', - 'form.verification-code.placeholder': '验证码', - 'form.title.label': '标题', - 'form.title.placeholder': '给目标起个名字', - 'form.date.label': '起止日期', - 'form.date.placeholder.start': '开始日期', - 'form.date.placeholder.end': '结束日期', - 'form.goal.label': '目标描述', - 'form.goal.placeholder': '请输入你的阶段性工作目标', - 'form.standard.label': '衡量标准', - 'form.standard.placeholder': '请输入衡量标准', - 'form.client.label': '客户', - 'form.client.label.tooltip': '目标的服务对象', - 'form.client.placeholder': '请描述你服务的客户,内部客户直接 @姓名/工号', - 'form.invites.label': '邀评人', - 'form.invites.placeholder': '请直接 @姓名/工号,最多可邀请 5 人', - 'form.weight.label': '权重', - 'form.weight.placeholder': '请输入', - 'form.public.label': '目标公开', - 'form.public.label.help': '客户、邀评人默认被分享', - 'form.public.radio.public': '公开', - 'form.public.radio.partially-public': '部分公开', - 'form.public.radio.private': '不公开', - 'form.publicUsers.placeholder': '公开给', - 'form.publicUsers.option.A': '同事甲', - 'form.publicUsers.option.B': '同事乙', - 'form.publicUsers.option.C': '同事丙', -}; diff --git a/src/locales/zh-CN/globalHeader.js b/src/locales/zh-CN/globalHeader.ts similarity index 100% rename from src/locales/zh-CN/globalHeader.js rename to src/locales/zh-CN/globalHeader.ts diff --git a/src/locales/zh-CN/login.js b/src/locales/zh-CN/login.js deleted file mode 100644 index e211e2cf28..0000000000 --- a/src/locales/zh-CN/login.js +++ /dev/null @@ -1,40 +0,0 @@ -export default { - 'app.login.userName': '用户名', - 'app.login.password': '密码', - 'app.login.message-invalid-credentials': '账户或密码错误(admin/ant.design)', - 'app.login.message-invalid-verification-code': '验证码错误', - 'app.login.tab-login-credentials': '账户密码登录', - 'app.login.tab-login-mobile': '手机号登录', - 'app.login.remember-me': '自动登录', - 'app.login.forgot-password': '忘记密码', - 'app.login.sign-in-with': '其他登录方式', - 'app.login.signup': '注册账户', - 'app.login.login': '登录', - 'app.register.register': '注册', - 'app.register.get-verification-code': '获取验证码', - 'app.login.verification-code-warning': - '此项目为演示项目,并不会真的给您发送验证码。请切换到账户密码登录界面按提示登录。', - 'app.register.sign-in': '使用已有账户登录', - 'app.register-result.msg': '你的账户:{email} 注册成功', - 'app.register-result.activation-email': - '激活邮件已发送到你的邮箱中,邮件有效期为24小时。请及时登录邮箱,点击邮件中的链接激活帐户。', - 'app.register-result.back-home': '返回首页', - 'app.register-result.view-mailbox': '查看邮箱', - 'validation.email.required': '请输入邮箱地址!', - 'validation.email.wrong-format': '邮箱地址格式错误!', - 'validation.userName.required': '请输入用户名!', - 'validation.password.required': '请输入密码!', - 'validation.password.twice': '两次输入的密码不匹配!', - 'validation.password.strength.msg': '请至少输入 6 个字符。请不要使用容易被猜到的密码。', - 'validation.password.strength.strong': '强度:强', - 'validation.password.strength.medium': '强度:中', - 'validation.password.strength.short': '强度:太短', - 'validation.confirm-password.required': '请确认密码!', - 'validation.phone-number.required': '请输入手机号!', - 'validation.phone-number.wrong-format': '手机号格式错误!', - 'validation.verification-code.required': '请输入验证码!', - 'validation.title.required': '请输入标题', - 'validation.date.required': '请选择起止日期', - 'validation.goal.required': '请输入目标描述', - 'validation.standard.required': '请输入衡量标准', -}; diff --git a/src/locales/zh-CN/menu.js b/src/locales/zh-CN/menu.ts similarity index 56% rename from src/locales/zh-CN/menu.js rename to src/locales/zh-CN/menu.ts index c057bb2a9c..f851fe9675 100644 --- a/src/locales/zh-CN/menu.js +++ b/src/locales/zh-CN/menu.ts @@ -1,4 +1,6 @@ export default { + 'menu.welcome': '欢迎', + 'menu.more-blocks': '更多区块', 'menu.home': '首页', 'menu.login': '登录', 'menu.register': '注册', @@ -7,21 +9,24 @@ export default { 'menu.dashboard.analysis': '分析页', 'menu.dashboard.monitor': '监控页', 'menu.dashboard.workplace': '工作台', + 'menu.exception.403': '403', + 'menu.exception.404': '404', + 'menu.exception.500': '500', 'menu.form': '表单页', - 'menu.form.basicform': '基础表单', - 'menu.form.stepform': '分步表单', - 'menu.form.stepform.info': '分步表单(填写转账信息)', - 'menu.form.stepform.confirm': '分步表单(确认转账信息)', - 'menu.form.stepform.result': '分步表单(完成)', - 'menu.form.advancedform': '高级表单', + 'menu.form.basic-form': '基础表单', + 'menu.form.step-form': '分步表单', + 'menu.form.step-form.info': '分步表单(填写转账信息)', + 'menu.form.step-form.confirm': '分步表单(确认转账信息)', + 'menu.form.step-form.result': '分步表单(完成)', + 'menu.form.advanced-form': '高级表单', 'menu.list': '列表页', - 'menu.list.searchtable': '查询表格', - 'menu.list.basiclist': '标准列表', - 'menu.list.cardlist': '卡片列表', - 'menu.list.searchlist': '搜索列表', - 'menu.list.searchlist.articles': '搜索列表(文章)', - 'menu.list.searchlist.projects': '搜索列表(项目)', - 'menu.list.searchlist.applications': '搜索列表(应用)', + 'menu.list.table-list': '查询表格', + 'menu.list.basic-list': '标准列表', + 'menu.list.card-list': '卡片列表', + 'menu.list.search-list': '搜索列表', + 'menu.list.search-list.articles': '搜索列表(文章)', + 'menu.list.search-list.projects': '搜索列表(项目)', + 'menu.list.search-list.applications': '搜索列表(应用)', 'menu.profile': '详情页', 'menu.profile.basic': '基础详情页', 'menu.profile.advanced': '高级详情页', diff --git a/src/locales/zh-CN/monitor.js b/src/locales/zh-CN/monitor.js deleted file mode 100644 index 3a3e3f0b55..0000000000 --- a/src/locales/zh-CN/monitor.js +++ /dev/null @@ -1,18 +0,0 @@ -export default { - 'app.monitor.trading-activity': '活动实时交易情况', - 'app.monitor.total-transactions': '今日交易总额', - 'app.monitor.sales-target': '销售目标完成率', - 'app.monitor.remaining-time': '活动剩余时间', - 'app.monitor.total-transactions-per-second': '每秒交易总额', - 'app.monitor.activity-forecast': '活动情况预测', - 'app.monitor.efficiency': '券核效率', - 'app.monitor.ratio': '跳出率', - 'app.monitor.proportion-per-category': '各品类占比', - 'app.monitor.fast-food': '中式快餐', - 'app.monitor.western-food': '西餐', - 'app.monitor.hot-pot': '火锅', - 'app.monitor.waiting-for-implementation': 'Waiting for implementation', - 'app.monitor.popular-searches': '热门搜索', - 'app.monitor.resource-surplus': '资源剩余', - 'app.monitor.fund-surplus': '补贴资金剩余', -}; diff --git a/src/locales/zh-CN/pwa.js b/src/locales/zh-CN/pwa.ts similarity index 100% rename from src/locales/zh-CN/pwa.js rename to src/locales/zh-CN/pwa.ts diff --git a/src/locales/zh-CN/result.js b/src/locales/zh-CN/result.js deleted file mode 100644 index cba0e1c1c5..0000000000 --- a/src/locales/zh-CN/result.js +++ /dev/null @@ -1,27 +0,0 @@ -export default { - 'app.result.error.title': '提交失败', - 'app.result.error.description': '请核对并修改以下信息后,再重新提交。', - 'app.result.error.hint-title': '您提交的内容有如下错误:', - 'app.result.error.hint-text1': '您的账户已被冻结', - 'app.result.error.hint-btn1': '立即解冻', - 'app.result.error.hint-text2': '您的账户还不具备申请资格', - 'app.result.error.hint-btn2': '立即升级', - 'app.result.error.btn-text': '返回修改', - 'app.result.success.title': '提交成功', - 'app.result.success.description': - '提交结果页用于反馈一系列操作任务的处理结果, 如果仅是简单操作,使用 Message 全局提示反馈即可。 本文字区域可以展示简单的补充说明,如果有类似展示 “单据”的需求,下面这个灰色区域可以呈现比较复杂的内容。', - 'app.result.success.operate-title': '项目名称', - 'app.result.success.operate-id': '项目 ID:', - 'app.result.success.principal': '负责人:', - 'app.result.success.operate-time': '生效时间:', - 'app.result.success.step1-title': '创建项目', - 'app.result.success.step1-operator': '曲丽丽', - 'app.result.success.step2-title': '部门初审', - 'app.result.success.step2-operator': '周毛毛', - 'app.result.success.step2-extra': '催一下', - 'app.result.success.step3-title': '财务复核', - 'app.result.success.step4-title': '完成', - 'app.result.success.btn-return': '返回列表', - 'app.result.success.btn-project': '查看项目', - 'app.result.success.btn-print': '打印', -}; diff --git a/src/locales/zh-CN/settingDrawer.js b/src/locales/zh-CN/settingDrawer.ts similarity index 100% rename from src/locales/zh-CN/settingDrawer.js rename to src/locales/zh-CN/settingDrawer.ts diff --git a/src/locales/zh-CN/settings.js b/src/locales/zh-CN/settings.ts similarity index 100% rename from src/locales/zh-CN/settings.js rename to src/locales/zh-CN/settings.ts diff --git a/src/locales/zh-TW.js b/src/locales/zh-TW.js deleted file mode 100644 index 33351509fb..0000000000 --- a/src/locales/zh-TW.js +++ /dev/null @@ -1,37 +0,0 @@ -import analysis from './zh-TW/analysis'; -import exception from './zh-TW/exception'; -import form from './zh-TW/form'; -import globalHeader from './zh-TW/globalHeader'; -import login from './zh-TW/login'; -import menu from './zh-TW/menu'; -import monitor from './zh-TW/monitor'; -import result from './zh-TW/result'; -import settingDrawer from './zh-TW/settingDrawer'; -import settings from './zh-TW/settings'; -import pwa from './zh-TW/pwa'; -import component from './zh-TW/component'; -import editor from './zh-TW/editor'; - -export default { - 'navBar.lang': '語言', - 'layout.user.link.help': '幫助', - 'layout.user.link.privacy': '隱私', - 'layout.user.link.terms': '條款', - 'app.home.introduce': '介紹', - 'app.forms.basic.title': '基礎表單', - 'app.forms.basic.description': - '表單頁用於向用戶收集或驗證信息,基礎表單常見於數據項較少的表單場景。', - ...analysis, - ...exception, - ...form, - ...globalHeader, - ...login, - ...menu, - ...monitor, - ...result, - ...settingDrawer, - ...settings, - ...pwa, - ...component, - ...editor, -}; diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts new file mode 100644 index 0000000000..1eeaffe205 --- /dev/null +++ b/src/locales/zh-TW.ts @@ -0,0 +1,20 @@ +import globalHeader from './zh-TW/globalHeader'; +import menu from './zh-TW/menu'; +import settingDrawer from './zh-TW/settingDrawer'; +import settings from './zh-TW/settings'; +import pwa from './zh-TW/pwa'; +import component from './zh-TW/component'; + +export default { + 'navBar.lang': '語言', + 'layout.user.link.help': '幫助', + 'layout.user.link.privacy': '隱私', + 'layout.user.link.terms': '條款', + 'app.preview.down.block': '下載此頁面到本地項目', + ...globalHeader, + ...menu, + ...settingDrawer, + ...settings, + ...pwa, + ...component, +}; diff --git a/src/locales/zh-TW/analysis.js b/src/locales/zh-TW/analysis.js deleted file mode 100644 index 7b2e37cf34..0000000000 --- a/src/locales/zh-TW/analysis.js +++ /dev/null @@ -1,34 +0,0 @@ -export default { - 'app.analysis.test': '工專路 {no} 號店', - 'app.analysis.introduce': '指標說明', - 'app.analysis.total-sales': '總銷售額', - 'app.analysis.day-sales': '日銷售額', - 'app.analysis.visits': '訪問量', - 'app.analysis.visits-trend': '訪問量趨勢', - 'app.analysis.visits-ranking': '門店訪問量排名', - 'app.analysis.day-visits': '日訪問量', - 'app.analysis.week': '周同比', - 'app.analysis.day': '日同比', - 'app.analysis.payments': '支付筆數', - 'app.analysis.conversion-rate': '轉化率', - 'app.analysis.operational-effect': '運營活動效果', - 'app.analysis.sales-trend': '銷售趨勢', - 'app.analysis.sales-ranking': '門店銷售額排名', - 'app.analysis.all-year': '全年', - 'app.analysis.all-month': '本月', - 'app.analysis.all-week': '本周', - 'app.analysis.all-day': '今日', - 'app.analysis.search-users': '搜索用戶數', - 'app.analysis.per-capita-search': '人均搜索次數', - 'app.analysis.online-top-search': '線上熱門搜索', - 'app.analysis.the-proportion-of-sales': '銷售額類別占比', - 'app.analysis.channel.all': '全部渠道', - 'app.analysis.channel.online': '線上', - 'app.analysis.channel.stores': '門店', - 'app.analysis.sales': '銷售額', - 'app.analysis.traffic': '客流量', - 'app.analysis.table.rank': '排名', - 'app.analysis.table.search-keyword': '搜索關鍵詞', - 'app.analysis.table.users': '用戶數', - 'app.analysis.table.weekly-range': '周漲幅', -}; diff --git a/src/locales/zh-TW/component.js b/src/locales/zh-TW/component.ts similarity index 72% rename from src/locales/zh-TW/component.js rename to src/locales/zh-TW/component.ts index dde9eb5998..ba48e299a9 100644 --- a/src/locales/zh-TW/component.js +++ b/src/locales/zh-TW/component.ts @@ -2,5 +2,4 @@ export default { 'component.tagSelect.expand': '展開', 'component.tagSelect.collapse': '收起', 'component.tagSelect.all': '全部', - 'component.miniProgress.tooltipDefault': '目标值', }; diff --git a/src/locales/zh-TW/editor.js b/src/locales/zh-TW/editor.js deleted file mode 100644 index d1d1377484..0000000000 --- a/src/locales/zh-TW/editor.js +++ /dev/null @@ -1,9 +0,0 @@ -export default { - 'app.editor.flow.title': '流程圖編輯器', - 'app.editor.flow.description': '千言萬語不如一張圖,流程圖是表示算法思路的好方法', - 'app.editor.koni.title': '拓撲編輯器', - 'app.editor.koni.description': '拓撲結構圖是指由網絡節點設備和通信介質構成的網絡結構圖', - 'app.editor.mind.title': '腦圖編輯器', - 'app.editor.mind.description': - '腦圖是表達發散性思維的有效圖形思維工具 ,它簡單卻又很有效,是一種實用性的思維工具', -}; diff --git a/src/locales/zh-TW/exception.js b/src/locales/zh-TW/exception.js deleted file mode 100644 index 119140d705..0000000000 --- a/src/locales/zh-TW/exception.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - 'app.exception.back': '返回首頁', - 'app.exception.description.403': '抱歉,妳無權訪問此頁面', - 'app.exception.description.404': '抱歉,妳訪問的頁面不存在', - 'app.exception.description.500': '抱歉,服務器出錯了', -}; diff --git a/src/locales/zh-TW/form.js b/src/locales/zh-TW/form.js deleted file mode 100644 index cf1adf548e..0000000000 --- a/src/locales/zh-TW/form.js +++ /dev/null @@ -1,37 +0,0 @@ -export default { - 'form.get-captcha': '獲取驗證碼', - 'form.captcha.second': '秒', - 'form.optional': '(選填)', - 'form.submit': '提交', - 'form.save': '保存', - 'form.email.placeholder': '郵箱', - 'form.password.placeholder': '至少6位密碼,區分大小寫', - 'form.confirm-password.placeholder': '確認密碼', - 'form.phone-number.placeholder': '手機號', - 'form.verification-code.placeholder': '驗證碼', - 'form.title.label': '標題', - 'form.title.placeholder': '給目標起個名字', - 'form.date.label': '起止日期', - 'form.date.placeholder.start': '開始日期', - 'form.date.placeholder.end': '結束日期', - 'form.goal.label': '目標描述', - 'form.goal.placeholder': '請輸入妳的階段性工作目標', - 'form.standard.label': '衡量標淮', - 'form.standard.placeholder': '請輸入衡量標淮', - 'form.client.label': '客戶', - 'form.client.label.tooltip': '目標的服務對象', - 'form.client.placeholder': '請描述妳服務的客戶,內部客戶直接 @姓名/工號', - 'form.invites.label': '邀評人', - 'form.invites.placeholder': '請直接 @姓名/工號,最多可邀請 5 人', - 'form.weight.label': '權重', - 'form.weight.placeholder': '請輸入', - 'form.public.label': '目標公開', - 'form.public.label.help': '客戶、邀評人默認被分享', - 'form.public.radio.public': '公開', - 'form.public.radio.partially-public': '部分公開', - 'form.public.radio.private': '不公開', - 'form.publicUsers.placeholder': '公開給', - 'form.publicUsers.option.A': '同事甲', - 'form.publicUsers.option.B': '同事乙', - 'form.publicUsers.option.C': '同事丙', -}; diff --git a/src/locales/zh-TW/globalHeader.js b/src/locales/zh-TW/globalHeader.ts similarity index 100% rename from src/locales/zh-TW/globalHeader.js rename to src/locales/zh-TW/globalHeader.ts diff --git a/src/locales/zh-TW/login.js b/src/locales/zh-TW/login.js deleted file mode 100644 index fb91660391..0000000000 --- a/src/locales/zh-TW/login.js +++ /dev/null @@ -1,40 +0,0 @@ -export default { - 'app.login.userName': '賬戶', - 'app.login.password': '密碼', - 'app.login.message-invalid-credentials': '賬戶或密碼錯誤(admin/ant.design)', - 'app.login.message-invalid-verification-code': '驗證碼錯誤', - 'app.login.tab-login-credentials': '賬戶密碼登錄', - 'app.login.tab-login-mobile': '手機號登錄', - 'app.login.remember-me': '自動登錄', - 'app.login.forgot-password': '忘記密碼', - 'app.login.sign-in-with': '其他登錄方式', - 'app.login.signup': '註冊賬戶', - 'app.login.login': '登錄', - 'app.register.register': '註冊', - 'app.register.get-verification-code': '獲取驗證碼', - 'app.login.verification-code-warning': - '此項目為演示項目,並不會真的給您發送驗證碼。請切換到賬戶密碼登錄界面按提示登錄。', - 'app.register.sign-in': '使用已有賬戶登錄', - 'app.register-result.msg': '妳的賬戶:{email} 註冊成功', - 'app.register-result.activation-email': - '激活郵件已發送到妳的郵箱中,郵件有效期為24小時。請及時登錄郵箱,點擊郵件中的鏈接激活帳戶。', - 'app.register-result.back-home': '返回首頁', - 'app.register-result.view-mailbox': '查看郵箱', - 'validation.email.required': '請輸入郵箱地址!', - 'validation.email.wrong-format': '郵箱地址格式錯誤!', - 'validation.userName.required': '請輸入賬戶!', - 'validation.password.required': '請輸入密碼!', - 'validation.password.twice': '兩次輸入的密碼不匹配!', - 'validation.password.strength.msg': '請至少輸入 6 個字符。請不要使用容易被猜到的密碼。', - 'validation.password.strength.strong': '強度:強', - 'validation.password.strength.medium': '強度:中', - 'validation.password.strength.short': '強度:太短', - 'validation.confirm-password.required': '請確認密碼!', - 'validation.phone-number.required': '請輸入手機號!', - 'validation.phone-number.wrong-format': '手機號格式錯誤!', - 'validation.verification-code.required': '請輸入驗證碼!', - 'validation.title.required': '請輸入標題', - 'validation.date.required': '請選擇起止日期', - 'validation.goal.required': '請輸入目標描述', - 'validation.standard.required': '請輸入衡量標淮', -}; diff --git a/src/locales/zh-TW/menu.js b/src/locales/zh-TW/menu.ts similarity index 56% rename from src/locales/zh-TW/menu.js rename to src/locales/zh-TW/menu.ts index 2b1a49ea4b..b0160286b6 100644 --- a/src/locales/zh-TW/menu.js +++ b/src/locales/zh-TW/menu.ts @@ -1,6 +1,12 @@ export default { + 'menu.welcome': '歡迎', + 'menu.more-blocks': '更多區塊', + 'menu.home': '首頁', 'menu.login': '登錄', + 'menu.exception.403': '403', + 'menu.exception.404': '404', + 'menu.exception.500': '500', 'menu.register': '註冊', 'menu.register.resultt': '註冊結果', 'menu.dashboard': 'Dashboard', @@ -8,20 +14,20 @@ export default { 'menu.dashboard.monitor': '監控頁', 'menu.dashboard.workplace': '工作臺', 'menu.form': '表單頁', - 'menu.form.basicform': '基礎表單', - 'menu.form.stepform': '分步表單', - 'menu.form.stepform.info': '分步表單(填寫轉賬信息)', - 'menu.form.stepform.confirm': '分步表單(確認轉賬信息)', - 'menu.form.stepform.result': '分步表單(完成)', - 'menu.form.advancedform': '高級表單', + 'menu.form.basic-form': '基礎表單', + 'menu.form.step-form': '分步表單', + 'menu.form.step-form.info': '分步表單(填寫轉賬信息)', + 'menu.form.step-form.confirm': '分步表單(確認轉賬信息)', + 'menu.form.step-form.result': '分步表單(完成)', + 'menu.form.advanced-form': '高級表單', 'menu.list': '列表頁', - 'menu.list.searchtable': '查詢表格', - 'menu.list.basiclist': '標淮列表', - 'menu.list.cardlist': '卡片列表', - 'menu.list.searchlist': '搜索列表', - 'menu.list.searchlist.articles': '搜索列表(文章)', - 'menu.list.searchlist.projects': '搜索列表(項目)', - 'menu.list.searchlist.applications': '搜索列表(應用)', + 'menu.list.table-list': '查詢表格', + 'menu.list.basic-list': '標淮列表', + 'menu.list.card-list': '卡片列表', + 'menu.list.search-list': '搜索列表', + 'menu.list.search-list.articles': '搜索列表(文章)', + 'menu.list.search-list.projects': '搜索列表(項目)', + 'menu.list.search-list.applications': '搜索列表(應用)', 'menu.profile': '詳情頁', 'menu.profile.basic': '基礎詳情頁', 'menu.profile.advanced': '高級詳情頁', diff --git a/src/locales/zh-TW/monitor.js b/src/locales/zh-TW/monitor.js deleted file mode 100644 index d19ac054d2..0000000000 --- a/src/locales/zh-TW/monitor.js +++ /dev/null @@ -1,18 +0,0 @@ -export default { - 'app.monitor.trading-activity': '活動實時交易情況', - 'app.monitor.total-transactions': '今日交易總額', - 'app.monitor.sales-target': '銷售目標完成率', - 'app.monitor.remaining-time': '活動剩余時間', - 'app.monitor.total-transactions-per-second': '每秒交易總額', - 'app.monitor.activity-forecast': '活動情況預測', - 'app.monitor.efficiency': '券核效率', - 'app.monitor.ratio': '跳出率', - 'app.monitor.proportion-per-category': '各品類占比', - 'app.monitor.fast-food': '中式快餐', - 'app.monitor.western-food': '西餐', - 'app.monitor.hot-pot': '火鍋', - 'app.monitor.waiting-for-implementation': 'Waiting for implementation', - 'app.monitor.popular-searches': '熱門搜索', - 'app.monitor.resource-surplus': '資源剩余', - 'app.monitor.fund-surplus': '補貼資金剩余', -}; diff --git a/src/locales/zh-TW/pwa.js b/src/locales/zh-TW/pwa.ts similarity index 100% rename from src/locales/zh-TW/pwa.js rename to src/locales/zh-TW/pwa.ts diff --git a/src/locales/zh-TW/result.js b/src/locales/zh-TW/result.js deleted file mode 100644 index a87b96e5c9..0000000000 --- a/src/locales/zh-TW/result.js +++ /dev/null @@ -1,27 +0,0 @@ -export default { - 'app.result.error.title': '提交失敗', - 'app.result.error.description': '請核對並修改以下信息後,再重新提交。', - 'app.result.error.hint-title': '您提交的內容有如下錯誤:', - 'app.result.error.hint-text1': '您的賬戶已被凍結', - 'app.result.error.hint-btn1': '立即解凍', - 'app.result.error.hint-text2': '您的賬戶還不具備申請資格', - 'app.result.error.hint-btn2': '立即升級', - 'app.result.error.btn-text': '返回修改', - 'app.result.success.title': '提交成功', - 'app.result.success.description': - '提交結果頁用於反饋壹系列操作任務的處理結果, 如果僅是簡單操作,使用 Message 全局提示反饋即可。 本文字區域可以展示簡單的補充說明,如果有類似展示 “單據”的需求,下面這個灰色區域可以呈現比較復雜的內容。', - 'app.result.success.operate-title': '項目名稱', - 'app.result.success.operate-id': '項目 ID:', - 'app.result.success.principal': '負責人:', - 'app.result.success.operate-time': '生效時間:', - 'app.result.success.step1-title': '創建項目', - 'app.result.success.step1-operator': '曲麗麗', - 'app.result.success.step2-title': '部門初審', - 'app.result.success.step2-operator': '周毛毛', - 'app.result.success.step2-extra': '催壹下', - 'app.result.success.step3-title': '財務復核', - 'app.result.success.step4-title': '完成', - 'app.result.success.btn-return': '返回列表', - 'app.result.success.btn-project': '查看項目', - 'app.result.success.btn-print': '打印', -}; diff --git a/src/locales/zh-TW/settingDrawer.js b/src/locales/zh-TW/settingDrawer.ts similarity index 100% rename from src/locales/zh-TW/settingDrawer.js rename to src/locales/zh-TW/settingDrawer.ts diff --git a/src/locales/zh-TW/settings.js b/src/locales/zh-TW/settings.ts similarity index 100% rename from src/locales/zh-TW/settings.js rename to src/locales/zh-TW/settings.ts diff --git a/src/models/connect.d.ts b/src/models/connect.d.ts new file mode 100644 index 0000000000..07b427a54d --- /dev/null +++ b/src/models/connect.d.ts @@ -0,0 +1,56 @@ +import { EffectsCommandMap } from 'dva'; +import { AnyAction } from 'redux'; +import { RouterTypes } from 'umi'; +import { GlobalModelState } from './global'; +import { UserModelState } from './user'; +import { DefaultSettings as SettingModelState } from '../../config/defaultSettings'; +import { MenuDataItem } from '@ant-design/pro-layout'; +export { GlobalModelState, SettingModelState, UserModelState }; + +export type Effect = ( + action: AnyAction, + effects: EffectsCommandMap & { select: (func: (state: ConnectState) => T) => T }, +) => void; + +/** + * @type P: Type of payload + * @type C: Type of callback + */ +export type Dispatch =

    void>(action: { + type: string; + payload?: P; + callback?: C; + [key: string]: any; +}) => any; + +export interface Loading { + global: boolean; + effects: { [key: string]: boolean | undefined }; + models: { + global?: boolean; + menu?: boolean; + setting?: boolean; + user?: boolean; + }; +} + +export interface ConnectState { + global: GlobalModelState; + loading: Loading; + settings: SettingModelState; + user: UserModelState; +} + +export interface Route extends MenuDataItem { + routes?: Route[]; +} + +/** + * @type T: Params matched in dynamic routing + */ +export interface ConnectProps + extends Partial> { + dispatch?: Dispatch; +} + +export default ConnectState; diff --git a/src/models/global.js b/src/models/global.ts similarity index 56% rename from src/models/global.js rename to src/models/global.ts index 34cff599b1..24a32d106f 100644 --- a/src/models/global.js +++ b/src/models/global.ts @@ -1,6 +1,37 @@ -import { queryNotices } from '@/services/api'; +import { queryNotices } from '@/services/user'; +import { Subscription } from 'dva'; +import { Reducer } from 'redux'; +import { Effect } from './connect'; +import { NoticeIconData } from '@/components/NoticeIcon'; -export default { +export interface NoticeItem extends NoticeIconData { + id: string; + type: string; + [key: string]: any; +} + +export interface GlobalModelState { + collapsed: boolean; + notices: NoticeItem[]; +} + +export interface GlobalModelType { + namespace: 'global'; + state: GlobalModelState; + effects: { + fetchNotices: Effect; + clearNotices: Effect; + changeNoticeReadState: Effect; + }; + reducers: { + changeLayoutCollapsed: Reducer; + saveNotices: Reducer; + saveClearedNotices: Reducer; + }; + subscriptions: { setup: Subscription }; +} + +const GlobalModel: GlobalModelType = { namespace: 'global', state: { @@ -15,8 +46,8 @@ export default { type: 'saveNotices', payload: data, }); - const unreadCount = yield select( - state => state.global.notices.filter(item => !item.read).length + const unreadCount: number = yield select( + state => state.global.notices.filter(item => !item.read).length, ); yield put({ type: 'user/changeNotifyCount', @@ -31,9 +62,9 @@ export default { type: 'saveClearedNotices', payload, }); - const count = yield select(state => state.global.notices.length); - const unreadCount = yield select( - state => state.global.notices.filter(item => !item.read).length + const count: number = yield select(state => state.global.notices.length); + const unreadCount: number = yield select( + state => state.global.notices.filter(item => !item.read).length, ); yield put({ type: 'user/changeNotifyCount', @@ -44,14 +75,14 @@ export default { }); }, *changeNoticeReadState({ payload }, { put, select }) { - const notices = yield select(state => + const notices: NoticeItem[] = yield select(state => state.global.notices.map(item => { const notice = { ...item }; if (notice.id === payload) { notice.read = true; } return notice; - }) + }), ); yield put({ type: 'saveNotices', @@ -68,7 +99,7 @@ export default { }, reducers: { - changeLayoutCollapsed(state, { payload }) { + changeLayoutCollapsed(state = { notices: [], collapsed: true }, { payload }) { return { ...state, collapsed: payload, @@ -76,12 +107,14 @@ export default { }, saveNotices(state, { payload }) { return { + collapsed: false, ...state, notices: payload, }; }, - saveClearedNotices(state, { payload }) { + saveClearedNotices(state = { notices: [], collapsed: true }, { payload }) { return { + collapsed: false, ...state, notices: state.notices.filter(item => item.type !== payload), }; @@ -92,10 +125,12 @@ export default { setup({ history }) { // Subscribe history(url) change, trigger `load` action if pathname is `/` return history.listen(({ pathname, search }) => { - if (typeof window.ga !== 'undefined') { - window.ga('send', 'pageview', pathname + search); + if (typeof (window as any).ga !== 'undefined') { + (window as any).ga('send', 'pageview', pathname + search); } }); }, }, }; + +export default GlobalModel; diff --git a/src/models/list.js b/src/models/list.js deleted file mode 100644 index 4758edaaa0..0000000000 --- a/src/models/list.js +++ /dev/null @@ -1,54 +0,0 @@ -import { queryFakeList, removeFakeList, addFakeList, updateFakeList } from '@/services/api'; - -export default { - namespace: 'list', - - state: { - list: [], - }, - - effects: { - *fetch({ payload }, { call, put }) { - const response = yield call(queryFakeList, payload); - yield put({ - type: 'queryList', - payload: Array.isArray(response) ? response : [], - }); - }, - *appendFetch({ payload }, { call, put }) { - const response = yield call(queryFakeList, payload); - yield put({ - type: 'appendList', - payload: Array.isArray(response) ? response : [], - }); - }, - *submit({ payload }, { call, put }) { - let callback; - if (payload.id) { - callback = Object.keys(payload).length === 1 ? removeFakeList : updateFakeList; - } else { - callback = addFakeList; - } - const response = yield call(callback, payload); // post - yield put({ - type: 'queryList', - payload: response, - }); - }, - }, - - reducers: { - queryList(state, action) { - return { - ...state, - list: action.payload, - }; - }, - appendList(state, action) { - return { - ...state, - list: state.list.concat(action.payload), - }; - }, - }, -}; diff --git a/src/models/login.js b/src/models/login.js deleted file mode 100644 index 5d129e1747..0000000000 --- a/src/models/login.js +++ /dev/null @@ -1,81 +0,0 @@ -import { routerRedux } from 'dva/router'; -import { stringify } from 'qs'; -import { fakeAccountLogin, getFakeCaptcha } from '@/services/api'; -import { setAuthority } from '@/utils/authority'; -import { getPageQuery } from '@/utils/utils'; -import { reloadAuthorized } from '@/utils/Authorized'; - -export default { - namespace: 'login', - - state: { - status: undefined, - }, - - effects: { - *login({ payload }, { call, put }) { - const response = yield call(fakeAccountLogin, payload); - yield put({ - type: 'changeLoginStatus', - payload: response, - }); - // Login successfully - if (response.status === 'ok') { - reloadAuthorized(); - const urlParams = new URL(window.location.href); - const params = getPageQuery(); - let { redirect } = params; - if (redirect) { - const redirectUrlParams = new URL(redirect); - if (redirectUrlParams.origin === urlParams.origin) { - redirect = redirect.substr(urlParams.origin.length); - if (redirect.match(/^\/.*#/)) { - redirect = redirect.substr(redirect.indexOf('#') + 1); - } - } else { - redirect = null; - } - } - yield put(routerRedux.replace(redirect || '/')); - } - }, - - *getCaptcha({ payload }, { call }) { - yield call(getFakeCaptcha, payload); - }, - - *logout(_, { put }) { - yield put({ - type: 'changeLoginStatus', - payload: { - status: false, - currentAuthority: 'guest', - }, - }); - reloadAuthorized(); - const { redirect } = getPageQuery(); - // redirect - if (window.location.pathname !== '/user/login' && !redirect) { - yield put( - routerRedux.replace({ - pathname: '/user/login', - search: stringify({ - redirect: window.location.href, - }), - }) - ); - } - }, - }, - - reducers: { - changeLoginStatus(state, { payload }) { - setAuthority(payload.currentAuthority); - return { - ...state, - status: payload.status, - type: payload.type, - }; - }, - }, -}; diff --git a/src/models/login.ts b/src/models/login.ts new file mode 100644 index 0000000000..18dfb97152 --- /dev/null +++ b/src/models/login.ts @@ -0,0 +1,61 @@ +import { routerRedux } from 'dva/router'; +import { Reducer, AnyAction } from 'redux'; +import { EffectsCommandMap } from 'dva'; +import { stringify, parse } from 'qs'; + +export function getPageQuery() { + return parse(window.location.href.split('?')[1]); +} + +export type Effect = ( + action: AnyAction, + effects: EffectsCommandMap & { select: (func: (state: {}) => T) => T }, +) => void; + +export interface ModelType { + namespace: string; + state: {}; + effects: { + logout: Effect; + }; + reducers: { + changeLoginStatus: Reducer<{}>; + }; +} + +const Model: ModelType = { + namespace: 'login', + + state: { + status: undefined, + }, + + effects: { + *logout(_, { put }) { + const { redirect } = getPageQuery(); + // redirect + if (window.location.pathname !== '/user/login' && !redirect) { + yield put( + routerRedux.replace({ + pathname: '/user/login', + search: stringify({ + redirect: window.location.href, + }), + }), + ); + } + }, + }, + + reducers: { + changeLoginStatus(state, { payload }) { + return { + ...state, + status: payload.status, + type: payload.type, + }; + }, + }, +}; + +export default Model; diff --git a/src/models/menu.js b/src/models/menu.js deleted file mode 100644 index 3d98f2d846..0000000000 --- a/src/models/menu.js +++ /dev/null @@ -1,131 +0,0 @@ -import memoizeOne from 'memoize-one'; -import isEqual from 'lodash/isEqual'; -import { formatMessage } from 'umi-plugin-react/locale'; -import Authorized from '@/utils/Authorized'; -import { menu } from '../defaultSettings'; - -const { check } = Authorized; - -// Conversion router to menu. -function formatter(data, parentAuthority, parentName) { - if (!data) { - return undefined; - } - return data - .map(item => { - if (!item.name || !item.path) { - return null; - } - - let locale = 'menu'; - if (parentName && parentName !== '/') { - locale = `${parentName}.${item.name}`; - } else { - locale = `menu.${item.name}`; - } - // if enableMenuLocale use item.name, - // close menu international - const name = menu.disableLocal - ? item.name - : formatMessage({ id: locale, defaultMessage: item.name }); - const result = { - ...item, - name, - locale, - authority: item.authority || parentAuthority, - }; - if (item.routes) { - const children = formatter(item.routes, item.authority, locale); - // Reduce memory usage - result.children = children; - } - delete result.routes; - return result; - }) - .filter(item => item); -} - -const memoizeOneFormatter = memoizeOne(formatter, isEqual); - -/** - * get SubMenu or Item - */ -const getSubMenu = item => { - // doc: add hideChildrenInMenu - if (item.children && !item.hideChildrenInMenu && item.children.some(child => child.name)) { - return { - ...item, - children: filterMenuData(item.children), // eslint-disable-line - }; - } - return item; -}; - -/** - * filter menuData - */ -const filterMenuData = menuData => { - if (!menuData) { - return []; - } - return menuData - .filter(item => item.name && !item.hideInMenu) - .map(item => check(item.authority, getSubMenu(item))) - .filter(item => item); -}; -/** - * 获取面包屑映射 - * @param {Object} menuData 菜单配置 - */ -const getBreadcrumbNameMap = menuData => { - if (!menuData) { - return {}; - } - const routerMap = {}; - - const flattenMenuData = data => { - data.forEach(menuItem => { - if (menuItem.children) { - flattenMenuData(menuItem.children); - } - // Reduce memory usage - routerMap[menuItem.path] = menuItem; - }); - }; - flattenMenuData(menuData); - return routerMap; -}; - -const memoizeOneGetBreadcrumbNameMap = memoizeOne(getBreadcrumbNameMap, isEqual); - -export default { - namespace: 'menu', - - state: { - menuData: [], - routerData: [], - breadcrumbNameMap: {}, - }, - - effects: { - *getMenuData({ payload }, { put }) { - const { routes, authority, path } = payload; - const originalMenuData = memoizeOneFormatter(routes, authority, path); - const menuData = filterMenuData(originalMenuData); - const breadcrumbNameMap = memoizeOneGetBreadcrumbNameMap(originalMenuData); - yield put({ - type: 'save', - payload: { menuData, breadcrumbNameMap, routerData: routes }, - }); - }, - }, - - reducers: { - save(state, action) { - return { - ...state, - ...action.payload, - }; - }, - }, -}; diff --git a/src/models/project.js b/src/models/project.js deleted file mode 100644 index cf894125d0..0000000000 --- a/src/models/project.js +++ /dev/null @@ -1,28 +0,0 @@ -import { queryProjectNotice } from '@/services/api'; - -export default { - namespace: 'project', - - state: { - notice: [], - }, - - effects: { - *fetchNotice(_, { call, put }) { - const response = yield call(queryProjectNotice); - yield put({ - type: 'saveNotice', - payload: Array.isArray(response) ? response : [], - }); - }, - }, - - reducers: { - saveNotice(state, action) { - return { - ...state, - notice: action.payload, - }; - }, - }, -}; diff --git a/src/models/setting.js b/src/models/setting.ts similarity index 72% rename from src/models/setting.js rename to src/models/setting.ts index 3956ed3d0f..a5a278ae89 100644 --- a/src/models/setting.js +++ b/src/models/setting.ts @@ -1,10 +1,21 @@ import { message } from 'antd'; -import defaultSettings from '../defaultSettings'; +import { Reducer } from 'redux'; +import defaultSettings, { DefaultSettings } from '../../config/defaultSettings'; -let lessNodesAppended; -const updateTheme = primaryColor => { +export interface SettingModelType { + namespace: 'settings'; + state: DefaultSettings; + reducers: { + getSetting: Reducer; + changeSetting: Reducer; + }; +} +let lessNodesAppended: boolean; + +const updateTheme: (primaryColor?: string) => void = primaryColor => { // Don't compile less in production! - // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 + // preview.pro.ant.design only do not use in your production; + // preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 if (ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION !== 'site') { return; } @@ -14,11 +25,12 @@ const updateTheme = primaryColor => { } const hideMessage = message.loading('正在编译主题!', 0); function buildIt() { - if (!window.less) { - return; + if (!(window as any).less) { + // tslint:disable-next-line no-console + return console.log('no less'); } setTimeout(() => { - window.less + (window as any).less .modifyVars({ '@primary-color': primaryColor, }) @@ -60,16 +72,19 @@ const updateTheme = primaryColor => { } }; -const updateColorWeak = colorWeak => { - document.body.className = colorWeak ? 'colorWeak' : ''; +const updateColorWeak: (colorWeak: boolean) => void = colorWeak => { + const root = document.getElementById('root'); + if (root) { + root.className = colorWeak ? 'colorWeak' : ''; + } }; -export default { - namespace: 'setting', +const SettingModel: SettingModelType = { + namespace: 'settings', state: defaultSettings, reducers: { - getSetting(state) { - const setting = {}; + getSetting(state = defaultSettings) { + const setting: Partial = {}; const urlParams = new URL(window.location.href); Object.keys(state).forEach(key => { if (urlParams.searchParams.has(key)) { @@ -78,16 +93,17 @@ export default { } }); const { primaryColor, colorWeak } = setting; + if (state.primaryColor !== primaryColor) { updateTheme(primaryColor); } - updateColorWeak(colorWeak); + updateColorWeak(!!colorWeak); return { ...state, ...setting, }; }, - changeSetting(state, { payload }) { + changeSetting(state = defaultSettings, { payload }) { const urlParams = new URL(window.location.href); Object.keys(defaultSettings).forEach(key => { if (urlParams.searchParams.has(key)) { @@ -122,3 +138,4 @@ export default { }, }, }; +export default SettingModel; diff --git a/src/models/user.js b/src/models/user.ts similarity index 52% rename from src/models/user.js rename to src/models/user.ts index c84ebbcfc8..8f3b208a87 100644 --- a/src/models/user.js +++ b/src/models/user.ts @@ -1,10 +1,42 @@ import { query as queryUsers, queryCurrent } from '@/services/user'; +import { Effect } from 'dva'; +import { Reducer } from 'redux'; -export default { +export interface CurrentUser { + avatar?: string; + name?: string; + title?: string; + group?: string; + signature?: string; + geographic?: any; + tags?: { + key: string; + label: string; + }[]; + unreadCount?: number; +} + +export interface UserModelState { + currentUser?: CurrentUser; +} + +export interface UserModelType { + namespace: 'user'; + state: UserModelState; + effects: { + fetch: Effect; + fetchCurrent: Effect; + }; + reducers: { + saveCurrentUser: Reducer; + changeNotifyCount: Reducer; + }; +} + +const UserModel: UserModelType = { namespace: 'user', state: { - list: [], currentUser: {}, }, @@ -26,19 +58,18 @@ export default { }, reducers: { - save(state, action) { - return { - ...state, - list: action.payload, - }; - }, saveCurrentUser(state, action) { return { ...state, currentUser: action.payload || {}, }; }, - changeNotifyCount(state, action) { + changeNotifyCount( + state = { + currentUser: {}, + }, + action, + ) { return { ...state, currentUser: { @@ -50,3 +81,5 @@ export default { }, }, }; + +export default UserModel; diff --git a/src/pages/404.js b/src/pages/404.js deleted file mode 100644 index ada3484e5e..0000000000 --- a/src/pages/404.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import Link from 'umi/link'; -import { formatMessage } from 'umi-plugin-react/locale'; -import Exception from '@/components/Exception'; - -export default () => ( - -); diff --git a/src/pages/Account/Center/Applications.js b/src/pages/Account/Center/Applications.js deleted file mode 100644 index 031686cd11..0000000000 --- a/src/pages/Account/Center/Applications.js +++ /dev/null @@ -1,88 +0,0 @@ -import React, { PureComponent } from 'react'; -import { List, Card, Icon, Dropdown, Menu, Avatar, Tooltip } from 'antd'; -import numeral from 'numeral'; -import { connect } from 'dva'; -import { formatWan } from '@/utils/utils'; -import stylesApplications from '../../List/Applications.less'; - -@connect(({ list }) => ({ - list, -})) -class Center extends PureComponent { - render() { - const { - list: { list }, - } = this.props; - const itemMenu = ( -

    - - - 1st menu item - - - - - 2nd menu item - - - - - 3d menu item - - - - ); - const CardInfo = ({ activeUser, newUser }) => ( -
    -
    -

    活跃用户

    -

    {activeUser}

    -
    -
    -

    新增用户

    -

    {newUser}

    -
    -
    - ); - return ( - ( - - - - , - - - , - - - , - - - , - ]} - > - } title={item.title} /> -
    - -
    -
    -
    - )} - /> - ); - } -} - -export default Center; diff --git a/src/pages/Account/Center/Articles.js b/src/pages/Account/Center/Articles.js deleted file mode 100644 index 9bb5ac309e..0000000000 --- a/src/pages/Account/Center/Articles.js +++ /dev/null @@ -1,59 +0,0 @@ -import React, { PureComponent } from 'react'; -import { List, Icon, Tag } from 'antd'; -import { connect } from 'dva'; -import ArticleListContent from '@/components/ArticleListContent'; -import styles from './Articles.less'; - -@connect(({ list }) => ({ - list, -})) -class Center extends PureComponent { - render() { - const { - list: { list }, - } = this.props; - const IconText = ({ type, text }) => ( - - - {text} - - ); - return ( - ( - , - , - , - ]} - > - - {item.title} - - } - description={ - - Ant Design - 设计语言 - 蚂蚁金服 - - } - /> - - - )} - /> - ); - } -} - -export default Center; diff --git a/src/pages/Account/Center/Articles.less b/src/pages/Account/Center/Articles.less deleted file mode 100644 index 2e51509ba7..0000000000 --- a/src/pages/Account/Center/Articles.less +++ /dev/null @@ -1,12 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.articleList { - :global { - .ant-list-item:first-child { - padding-top: 0; - } - } -} -a.listItemMetaTitle { - color: @heading-color; -} diff --git a/src/pages/Account/Center/Center.js b/src/pages/Account/Center/Center.js deleted file mode 100644 index d2512f95bc..0000000000 --- a/src/pages/Account/Center/Center.js +++ /dev/null @@ -1,216 +0,0 @@ -import React, { PureComponent } from 'react'; -import { connect } from 'dva'; -import Link from 'umi/link'; -import router from 'umi/router'; -import { Card, Row, Col, Icon, Avatar, Tag, Divider, Spin, Input } from 'antd'; -import GridContent from '@/components/PageHeaderWrapper/GridContent'; -import styles from './Center.less'; - -@connect(({ loading, user, project }) => ({ - listLoading: loading.effects['list/fetch'], - currentUser: user.currentUser, - currentUserLoading: loading.effects['user/fetchCurrent'], - project, - projectLoading: loading.effects['project/fetchNotice'], -})) -class Center extends PureComponent { - state = { - newTags: [], - inputVisible: false, - inputValue: '', - }; - - componentDidMount() { - const { dispatch } = this.props; - dispatch({ - type: 'user/fetchCurrent', - }); - dispatch({ - type: 'list/fetch', - payload: { - count: 8, - }, - }); - dispatch({ - type: 'project/fetchNotice', - }); - } - - onTabChange = key => { - const { match } = this.props; - switch (key) { - case 'articles': - router.push(`${match.url}/articles`); - break; - case 'applications': - router.push(`${match.url}/applications`); - break; - case 'projects': - router.push(`${match.url}/projects`); - break; - default: - break; - } - }; - - showInput = () => { - this.setState({ inputVisible: true }, () => this.input.focus()); - }; - - saveInputRef = input => { - this.input = input; - }; - - handleInputChange = e => { - this.setState({ inputValue: e.target.value }); - }; - - handleInputConfirm = () => { - const { state } = this; - const { inputValue } = state; - let { newTags } = state; - if (inputValue && newTags.filter(tag => tag.label === inputValue).length === 0) { - newTags = [...newTags, { key: `new-${newTags.length}`, label: inputValue }]; - } - this.setState({ - newTags, - inputVisible: false, - inputValue: '', - }); - }; - - render() { - const { newTags, inputVisible, inputValue } = this.state; - const { - listLoading, - currentUser, - currentUserLoading, - project: { notice }, - projectLoading, - match, - location, - children, - } = this.props; - - const operationTabList = [ - { - key: 'articles', - tab: ( - - 文章 (8) - - ), - }, - { - key: 'applications', - tab: ( - - 应用 (8) - - ), - }, - { - key: 'projects', - tab: ( - - 项目 (8) - - ), - }, - ]; - - return ( - - -
    - - {currentUser && Object.keys(currentUser).length ? ( -
    -
    - -
    {currentUser.name}
    -
    {currentUser.signature}
    -
    -
    -

    - - {currentUser.title} -

    -

    - - {currentUser.group} -

    -

    - - {currentUser.geographic.province.label} - {currentUser.geographic.city.label} -

    -
    - -
    -
    标签
    - {currentUser.tags.concat(newTags).map(item => ( - {item.label} - ))} - {inputVisible && ( - - )} - {!inputVisible && ( - - - - )} -
    - -
    -
    团队
    - - - {notice.map(item => ( -
    - - - {item.member} - - - ))} - - - - - ) : ( - 'loading...' - )} - - - - - {children} - - - - - ); - } -} - -export default Center; diff --git a/src/pages/Account/Center/Center.less b/src/pages/Account/Center/Center.less deleted file mode 100644 index f6434fafb5..0000000000 --- a/src/pages/Account/Center/Center.less +++ /dev/null @@ -1,97 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; -@import '~@/utils/utils.less'; - -.avatarHolder { - margin-bottom: 24px; - text-align: center; - - & > img { - width: 104px; - height: 104px; - margin-bottom: 20px; - } - - .name { - margin-bottom: 4px; - color: @heading-color; - font-weight: 500; - font-size: 20px; - line-height: 28px; - } -} - -.detail { - p { - position: relative; - margin-bottom: 8px; - padding-left: 26px; - - &:last-child { - margin-bottom: 0; - } - } - - i { - position: absolute; - top: 4px; - left: 0; - width: 14px; - height: 14px; - background: url(https://gw.alipayobjects.com/zos/rmsportal/pBjWzVAHnOOtAUvZmZfy.svg); - - &.title { - background-position: 0 0; - } - - &.group { - background-position: 0 -22px; - } - - &.address { - background-position: 0 -44px; - } - } -} - -.tagsTitle, -.teamTitle { - margin-bottom: 12px; - color: @heading-color; - font-weight: 500; -} - -.tags { - :global { - .ant-tag { - margin-bottom: 8px; - } - } -} - -.team { - :global { - .ant-avatar { - margin-right: 12px; - } - } - - a { - display: block; - margin-bottom: 24px; - color: @text-color; - transition: color 0.3s; - .textOverflow(); - - &:hover { - color: @primary-color; - } - } -} - -.tabsCard { - :global { - .ant-card-head { - padding: 0 16px; - } - } -} diff --git a/src/pages/Account/Center/Projects.js b/src/pages/Account/Center/Projects.js deleted file mode 100644 index ac749fdb58..0000000000 --- a/src/pages/Account/Center/Projects.js +++ /dev/null @@ -1,52 +0,0 @@ -import React, { PureComponent } from 'react'; -import { List, Card } from 'antd'; -import moment from 'moment'; -import { connect } from 'dva'; -import AvatarList from '@/components/AvatarList'; -import stylesProjects from '../../List/Projects.less'; - -@connect(({ list }) => ({ - list, -})) -class Center extends PureComponent { - render() { - const { - list: { list }, - } = this.props; - return ( - ( - - } - > - {item.title}} description={item.subDescription} /> -
    - {moment(item.updatedAt).fromNow()} -
    - - {item.members.map(member => ( - - ))} - -
    -
    -
    -
    - )} - /> - ); - } -} - -export default Center; diff --git a/src/pages/Account/Settings/BaseView.js b/src/pages/Account/Settings/BaseView.js deleted file mode 100644 index 040bd7b5c4..0000000000 --- a/src/pages/Account/Settings/BaseView.js +++ /dev/null @@ -1,192 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale'; -import { Form, Input, Upload, Select, Button } from 'antd'; -import { connect } from 'dva'; -import styles from './BaseView.less'; -import GeographicView from './GeographicView'; -import PhoneView from './PhoneView'; -// import { getTimeDistance } from '@/utils/utils'; - -const FormItem = Form.Item; -const { Option } = Select; - -// 头像组件 方便以后独立,增加裁剪之类的功能 -const AvatarView = ({ avatar }) => ( - -
    - -
    -
    - avatar -
    - -
    - -
    -
    -
    -); - -const validatorGeographic = (rule, value, callback) => { - const { province, city } = value; - if (!province.key) { - callback('Please input your province!'); - } - if (!city.key) { - callback('Please input your city!'); - } - callback(); -}; - -const validatorPhone = (rule, value, callback) => { - const values = value.split('-'); - if (!values[0]) { - callback('Please input your area code!'); - } - if (!values[1]) { - callback('Please input your phone number!'); - } - callback(); -}; - -@connect(({ user }) => ({ - currentUser: user.currentUser, -})) -@Form.create() -class BaseView extends Component { - componentDidMount() { - this.setBaseInfo(); - } - - setBaseInfo = () => { - const { currentUser, form } = this.props; - Object.keys(form.getFieldsValue()).forEach(key => { - const obj = {}; - obj[key] = currentUser[key] || null; - form.setFieldsValue(obj); - }); - }; - - getAvatarURL() { - const { currentUser } = this.props; - if (currentUser.avatar) { - return currentUser.avatar; - } - const url = 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png'; - return url; - } - - getViewDom = ref => { - this.view = ref; - }; - - render() { - const { - form: { getFieldDecorator }, - } = this.props; - return ( -
    -
    -
    - - {getFieldDecorator('email', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.email-message' }, {}), - }, - ], - })()} - - - {getFieldDecorator('name', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.nickname-message' }, {}), - }, - ], - })()} - - - {getFieldDecorator('profile', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.profile-message' }, {}), - }, - ], - })( - - )} - - - {getFieldDecorator('country', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.country-message' }, {}), - }, - ], - })( - - )} - - - {getFieldDecorator('geographic', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.geographic-message' }, {}), - }, - { - validator: validatorGeographic, - }, - ], - })()} - - - {getFieldDecorator('address', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.address-message' }, {}), - }, - ], - })()} - - - {getFieldDecorator('phone', { - rules: [ - { - required: true, - message: formatMessage({ id: 'app.settings.basic.phone-message' }, {}), - }, - { validator: validatorPhone }, - ], - })()} - - - -
    -
    - -
    -
    - ); - } -} - -export default BaseView; diff --git a/src/pages/Account/Settings/BaseView.less b/src/pages/Account/Settings/BaseView.less deleted file mode 100644 index e1b09e9370..0000000000 --- a/src/pages/Account/Settings/BaseView.less +++ /dev/null @@ -1,52 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.baseView { - display: flex; - padding-top: 12px; - - .left { - min-width: 224px; - max-width: 448px; - } - .right { - flex: 1; - padding-left: 104px; - .avatar_title { - height: 22px; - margin-bottom: 8px; - color: @heading-color; - font-size: @font-size-base; - line-height: 22px; - } - .avatar { - width: 144px; - height: 144px; - margin-bottom: 12px; - overflow: hidden; - img { - width: 100%; - } - } - .button_view { - width: 144px; - text-align: center; - } - } -} - -@media screen and (max-width: @screen-xl) { - .baseView { - flex-direction: column-reverse; - - .right { - display: flex; - flex-direction: column; - align-items: center; - max-width: 448px; - padding: 20px; - .avatar_title { - display: none; - } - } - } -} diff --git a/src/pages/Account/Settings/BindingView.js b/src/pages/Account/Settings/BindingView.js deleted file mode 100644 index f2908874d2..0000000000 --- a/src/pages/Account/Settings/BindingView.js +++ /dev/null @@ -1,60 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale'; -import { Icon, List } from 'antd'; - -class BindingView extends Component { - getData = () => [ - { - title: formatMessage({ id: 'app.settings.binding.taobao' }, {}), - description: formatMessage({ id: 'app.settings.binding.taobao-description' }, {}), - actions: [ - - - , - ], - avatar: , - }, - { - title: formatMessage({ id: 'app.settings.binding.alipay' }, {}), - description: formatMessage({ id: 'app.settings.binding.alipay-description' }, {}), - actions: [ - - - , - ], - avatar: , - }, - { - title: formatMessage({ id: 'app.settings.binding.dingding' }, {}), - description: formatMessage({ id: 'app.settings.binding.dingding-description' }, {}), - actions: [ - - - , - ], - avatar: , - }, - ]; - - render() { - return ( - - ( - - - - )} - /> - - ); - } -} - -export default BindingView; diff --git a/src/pages/Account/Settings/GeographicView.js b/src/pages/Account/Settings/GeographicView.js deleted file mode 100644 index d33cb13871..0000000000 --- a/src/pages/Account/Settings/GeographicView.js +++ /dev/null @@ -1,128 +0,0 @@ -import React, { PureComponent } from 'react'; -import { Select, Spin } from 'antd'; -import { connect } from 'dva'; -import styles from './GeographicView.less'; - -const { Option } = Select; - -const nullSlectItem = { - label: '', - key: '', -}; - -@connect(({ geographic }) => { - const { province, isLoading, city } = geographic; - return { - province, - city, - isLoading, - }; -}) -class GeographicView extends PureComponent { - componentDidMount = () => { - const { dispatch } = this.props; - dispatch({ - type: 'geographic/fetchProvince', - }); - }; - - componentDidUpdate(props) { - const { dispatch, value } = this.props; - - if (!props.value && !!value && !!value.province) { - dispatch({ - type: 'geographic/fetchCity', - payload: value.province.key, - }); - } - } - - getProvinceOption() { - const { province } = this.props; - return this.getOption(province); - } - - getCityOption = () => { - const { city } = this.props; - return this.getOption(city); - }; - - getOption = list => { - if (!list || list.length < 1) { - return ( - - ); - } - return list.map(item => ( - - )); - }; - - selectProvinceItem = item => { - const { dispatch, onChange } = this.props; - dispatch({ - type: 'geographic/fetchCity', - payload: item.key, - }); - onChange({ - province: item, - city: nullSlectItem, - }); - }; - - selectCityItem = item => { - const { value, onChange } = this.props; - onChange({ - province: value.province, - city: item, - }); - }; - - conversionObject() { - const { value } = this.props; - if (!value) { - return { - province: nullSlectItem, - city: nullSlectItem, - }; - } - const { province, city } = value; - return { - province: province || nullSlectItem, - city: city || nullSlectItem, - }; - } - - render() { - const { province, city } = this.conversionObject(); - const { isLoading } = this.props; - return ( - - - - - ); - } -} - -export default GeographicView; diff --git a/src/pages/Account/Settings/GeographicView.less b/src/pages/Account/Settings/GeographicView.less deleted file mode 100644 index fdc9750030..0000000000 --- a/src/pages/Account/Settings/GeographicView.less +++ /dev/null @@ -1,19 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.row { - .item { - width: 50%; - max-width: 220px; - } - .item:first-child { - width: ~'calc(50% - 8px)'; - margin-right: 8px; - } -} - -@media screen and (max-width: @screen-sm) { - .item:first-child { - margin: 0; - margin-bottom: 8px; - } -} diff --git a/src/pages/Account/Settings/Info.js b/src/pages/Account/Settings/Info.js deleted file mode 100644 index 2415de3887..0000000000 --- a/src/pages/Account/Settings/Info.js +++ /dev/null @@ -1,129 +0,0 @@ -import React, { Component } from 'react'; -import { connect } from 'dva'; -import router from 'umi/router'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import { Menu } from 'antd'; -import GridContent from '@/components/PageHeaderWrapper/GridContent'; -import styles from './Info.less'; - -const { Item } = Menu; - -@connect(({ user }) => ({ - currentUser: user.currentUser, -})) -class Info extends Component { - constructor(props) { - super(props); - const { match, location } = props; - const menuMap = { - base: , - security: ( - - ), - binding: ( - - ), - notification: ( - - ), - }; - const key = location.pathname.replace(`${match.path}/`, ''); - this.state = { - mode: 'inline', - menuMap, - selectKey: menuMap[key] ? key : 'base', - }; - } - - static getDerivedStateFromProps(props, state) { - const { match, location } = props; - let selectKey = location.pathname.replace(`${match.path}/`, ''); - selectKey = state.menuMap[selectKey] ? selectKey : 'base'; - if (selectKey !== state.selectKey) { - return { selectKey }; - } - return null; - } - - componentDidMount() { - window.addEventListener('resize', this.resize); - this.resize(); - } - - componentWillUnmount() { - window.removeEventListener('resize', this.resize); - } - - getmenu = () => { - const { menuMap } = this.state; - return Object.keys(menuMap).map(item => {menuMap[item]}); - }; - - getRightTitle = () => { - const { selectKey, menuMap } = this.state; - return menuMap[selectKey]; - }; - - selectKey = ({ key }) => { - router.push(`/account/settings/${key}`); - this.setState({ - selectKey: key, - }); - }; - - resize = () => { - if (!this.main) { - return; - } - - const { mode: currentMode } = this.state; - - let mode = 'inline'; - const { offsetWidth } = this.main; - - if (offsetWidth > 400 && offsetWidth < 641) { - mode = 'horizontal'; - } - - if (window.innerWidth < 768 && offsetWidth > 400) { - mode = 'horizontal'; - } - - if (mode !== currentMode) { - requestAnimationFrame(() => this.setState({ mode })); - } - }; - - render() { - const { children, currentUser } = this.props; - if (!currentUser.userid) { - return ''; - } - const { mode, selectKey } = this.state; - return ( - -
    { - this.main = ref; - }} - > -
    - - {this.getmenu()} - -
    -
    -
    {this.getRightTitle()}
    - {children} -
    -
    -
    - ); - } -} - -export default Info; diff --git a/src/pages/Account/Settings/Info.less b/src/pages/Account/Settings/Info.less deleted file mode 100644 index b391ad55ca..0000000000 --- a/src/pages/Account/Settings/Info.less +++ /dev/null @@ -1,97 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.main { - display: flex; - width: 100%; - height: 100%; - padding-top: 16px; - padding-bottom: 16px; - overflow: auto; - background-color: @body-background; - .leftmenu { - width: 224px; - border-right: @border-width-base @border-style-base @border-color-split; - :global { - .ant-menu-inline { - border: none; - } - .ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected { - font-weight: bold; - } - } - } - .right { - flex: 1; - padding-top: 8px; - padding-right: 40px; - padding-bottom: 8px; - padding-left: 40px; - .title { - margin-bottom: 12px; - color: @heading-color; - font-weight: 500; - font-size: 20px; - line-height: 28px; - } - } - :global { - .ant-list-split .ant-list-item:last-child { - border-bottom: 1px solid #e8e8e8; - } - .ant-list-item { - padding-top: 14px; - padding-bottom: 14px; - } - } -} -:global { - .ant-list-item-meta { - // 账号绑定图标 - .taobao { - display: block; - color: #ff4000; - font-size: 48px; - line-height: 48px; - border-radius: @border-radius-base; - } - .dingding { - margin: 2px; - padding: 6px; - color: #fff; - font-size: 32px; - line-height: 32px; - background-color: #2eabff; - border-radius: @border-radius-base; - } - .alipay { - color: #2eabff; - font-size: 48px; - line-height: 48px; - border-radius: @border-radius-base; - } - } - - // 密码强度 - font.strong { - color: @success-color; - } - font.medium { - color: @warning-color; - } - font.weak { - color: @error-color; - } -} - -@media screen and (max-width: @screen-md) { - .main { - flex-direction: column; - .leftmenu { - width: 100%; - border: none; - } - .right { - padding: 40px; - } - } -} diff --git a/src/pages/Account/Settings/NotificationView.js b/src/pages/Account/Settings/NotificationView.js deleted file mode 100644 index 00175ccfd3..0000000000 --- a/src/pages/Account/Settings/NotificationView.js +++ /dev/null @@ -1,50 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import { formatMessage } from 'umi-plugin-react/locale'; -import { Switch, List } from 'antd'; - -class NotificationView extends Component { - getData = () => { - const Action = ( - - ); - return [ - { - title: formatMessage({ id: 'app.settings.notification.password' }, {}), - description: formatMessage({ id: 'app.settings.notification.password-description' }, {}), - actions: [Action], - }, - { - title: formatMessage({ id: 'app.settings.notification.messages' }, {}), - description: formatMessage({ id: 'app.settings.notification.messages-description' }, {}), - actions: [Action], - }, - { - title: formatMessage({ id: 'app.settings.notification.todo' }, {}), - description: formatMessage({ id: 'app.settings.notification.todo-description' }, {}), - actions: [Action], - }, - ]; - }; - - render() { - return ( - - ( - - - - )} - /> - - ); - } -} - -export default NotificationView; diff --git a/src/pages/Account/Settings/PhoneView.js b/src/pages/Account/Settings/PhoneView.js deleted file mode 100644 index 2665527642..0000000000 --- a/src/pages/Account/Settings/PhoneView.js +++ /dev/null @@ -1,33 +0,0 @@ -import React, { Fragment, PureComponent } from 'react'; -import { Input } from 'antd'; -import styles from './PhoneView.less'; - -class PhoneView extends PureComponent { - render() { - const { value, onChange } = this.props; - let values = ['', '']; - if (value) { - values = value.split('-'); - } - return ( - - { - onChange(`${e.target.value}-${values[1]}`); - }} - /> - { - onChange(`${values[0]}-${e.target.value}`); - }} - value={values[1]} - /> - - ); - } -} - -export default PhoneView; diff --git a/src/pages/Account/Settings/PhoneView.less b/src/pages/Account/Settings/PhoneView.less deleted file mode 100644 index ee4328ebfa..0000000000 --- a/src/pages/Account/Settings/PhoneView.less +++ /dev/null @@ -1,11 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.area_code { - width: 30%; - max-width: 128px; - margin-right: 8px; -} -.phone_number { - width: ~'calc(70% - 8px)'; - max-width: 312px; -} diff --git a/src/pages/Account/Settings/SecurityView.js b/src/pages/Account/Settings/SecurityView.js deleted file mode 100644 index 96dbf32c0e..0000000000 --- a/src/pages/Account/Settings/SecurityView.js +++ /dev/null @@ -1,102 +0,0 @@ -import React, { Component, Fragment } from 'react'; -import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale'; -import { List } from 'antd'; -// import { getTimeDistance } from '@/utils/utils'; - -const passwordStrength = { - strong: ( - - - - ), - medium: ( - - - - ), - weak: ( - - - Weak - - ), -}; - -class SecurityView extends Component { - getData = () => [ - { - title: formatMessage({ id: 'app.settings.security.password' }, {}), - description: ( - - {formatMessage({ id: 'app.settings.security.password-description' })}: - {passwordStrength.strong} - - ), - actions: [ - - - , - ], - }, - { - title: formatMessage({ id: 'app.settings.security.phone' }, {}), - description: `${formatMessage( - { id: 'app.settings.security.phone-description' }, - {} - )}:138****8293`, - actions: [ - - - , - ], - }, - { - title: formatMessage({ id: 'app.settings.security.question' }, {}), - description: formatMessage({ id: 'app.settings.security.question-description' }, {}), - actions: [ - - - , - ], - }, - { - title: formatMessage({ id: 'app.settings.security.email' }, {}), - description: `${formatMessage( - { id: 'app.settings.security.email-description' }, - {} - )}:ant***sign.com`, - actions: [ - - - , - ], - }, - { - title: formatMessage({ id: 'app.settings.security.mfa' }, {}), - description: formatMessage({ id: 'app.settings.security.mfa-description' }, {}), - actions: [ - - - , - ], - }, - ]; - - render() { - return ( - - ( - - - - )} - /> - - ); - } -} - -export default SecurityView; diff --git a/src/pages/Account/Settings/models/geographic.js b/src/pages/Account/Settings/models/geographic.js deleted file mode 100644 index a501920c71..0000000000 --- a/src/pages/Account/Settings/models/geographic.js +++ /dev/null @@ -1,65 +0,0 @@ -import { queryProvince, queryCity } from '@/services/geographic'; - -export default { - namespace: 'geographic', - - state: { - province: [], - city: [], - isLoading: false, - }, - - effects: { - *fetchProvince(_, { call, put }) { - yield put({ - type: 'changeLoading', - payload: true, - }); - const response = yield call(queryProvince); - yield put({ - type: 'setProvince', - payload: response, - }); - yield put({ - type: 'changeLoading', - payload: false, - }); - }, - *fetchCity({ payload }, { call, put }) { - yield put({ - type: 'changeLoading', - payload: true, - }); - const response = yield call(queryCity, payload); - yield put({ - type: 'setCity', - payload: response, - }); - yield put({ - type: 'changeLoading', - payload: false, - }); - }, - }, - - reducers: { - setProvince(state, action) { - return { - ...state, - province: action.payload, - }; - }, - setCity(state, action) { - return { - ...state, - city: action.payload, - }; - }, - changeLoading(state, action) { - return { - ...state, - isLoading: action.payload, - }; - }, - }, -}; diff --git a/src/pages/Authorized.js b/src/pages/Authorized.js deleted file mode 100644 index 5889812b68..0000000000 --- a/src/pages/Authorized.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import Redirect from 'umi/redirect'; -import pathToRegexp from 'path-to-regexp'; -import { connect } from 'dva'; -import Authorized from '@/utils/Authorized'; -import { getAuthority } from '@/utils/authority'; -import Exception403 from '@/pages/Exception/403'; - -function AuthComponent({ children, location, routerData }) { - const auth = getAuthority(); - const isLogin = auth && auth[0] !== 'guest'; - const getRouteAuthority = (path, routeData) => { - let authorities; - routeData.forEach(route => { - // match prefix - if (pathToRegexp(`${route.path}(.*)`).test(path)) { - authorities = route.authority || authorities; - - // get children authority recursively - if (route.routes) { - authorities = getRouteAuthority(path, route.routes) || authorities; - } - } - }); - return authorities; - }; - return ( - : } - > - {children} - - ); -} -export default connect(({ menu: menuModel }) => ({ - routerData: menuModel.routerData, -}))(AuthComponent); diff --git a/src/pages/Authorized.tsx b/src/pages/Authorized.tsx new file mode 100644 index 0000000000..6f502d3684 --- /dev/null +++ b/src/pages/Authorized.tsx @@ -0,0 +1,50 @@ +import Authorized from '@/utils/Authorized'; +import { ConnectProps, ConnectState, UserModelState, Route } from '@/models/connect'; +import { connect } from 'dva'; +import pathToRegexp from 'path-to-regexp'; +import React from 'react'; +import Redirect from 'umi/redirect'; + +interface AuthComponentProps extends ConnectProps { + user: UserModelState; +} + +const getRouteAuthority = (path: string, routeData: Route[]) => { + let authorities: string[] | string | undefined = undefined; + routeData.forEach(route => { + // match prefix + if (pathToRegexp(`${route.path}(.*)`).test(path)) { + authorities = route.authority || authorities; + // get children authority recursively + if (route.routes) { + authorities = getRouteAuthority(path, route.routes) || authorities; + } + } + }); + return authorities; +}; + +const AuthComponent: React.FC = ({ + children, + route = { + routes: [], + }, + location, + user, +}) => { + const { currentUser } = user; + const { routes = [] } = route; + const isLogin = currentUser && currentUser.name; + return ( + : } + > + {children} + + ); +}; + +export default connect(({ user }: ConnectState) => ({ + user, +}))(AuthComponent); diff --git a/src/pages/Dashboard/Analysis.js b/src/pages/Dashboard/Analysis.js deleted file mode 100644 index e76271ac72..0000000000 --- a/src/pages/Dashboard/Analysis.js +++ /dev/null @@ -1,180 +0,0 @@ -import React, { Component, Suspense } from 'react'; -import { connect } from 'dva'; -import { Row, Col, Icon, Menu, Dropdown } from 'antd'; -import GridContent from '@/components/PageHeaderWrapper/GridContent'; -import { getTimeDistance } from '@/utils/utils'; -import styles from './Analysis.less'; -import PageLoading from '@/components/PageLoading'; - -const IntroduceRow = React.lazy(() => import('./IntroduceRow')); -const SalesCard = React.lazy(() => import('./SalesCard')); -const TopSearch = React.lazy(() => import('./TopSearch')); -const ProportionSales = React.lazy(() => import('./ProportionSales')); -const OfflineData = React.lazy(() => import('./OfflineData')); - -@connect(({ chart, loading }) => ({ - chart, - loading: loading.effects['chart/fetch'], -})) -class Analysis extends Component { - state = { - salesType: 'all', - currentTabKey: '', - rangePickerValue: getTimeDistance('year'), - }; - - componentDidMount() { - const { dispatch } = this.props; - this.reqRef = requestAnimationFrame(() => { - dispatch({ - type: 'chart/fetch', - }); - }); - } - - componentWillUnmount() { - cancelAnimationFrame(this.reqRef); - } - - handleChangeSalesType = e => { - this.setState({ - salesType: e.target.value, - }); - }; - - handleTabChange = key => { - this.setState({ - currentTabKey: key, - }); - }; - - handleRangePickerChange = rangePickerValue => { - const { dispatch } = this.props; - this.setState({ - rangePickerValue, - }); - - dispatch({ - type: 'chart/fetchSalesData', - }); - }; - - selectDate = type => { - const { dispatch } = this.props; - this.setState({ - rangePickerValue: getTimeDistance(type), - }); - - dispatch({ - type: 'chart/fetchSalesData', - }); - }; - - isActive = type => { - const { rangePickerValue } = this.state; - const value = getTimeDistance(type); - if (!rangePickerValue[0] || !rangePickerValue[1]) { - return ''; - } - if ( - rangePickerValue[0].isSame(value[0], 'day') && - rangePickerValue[1].isSame(value[1], 'day') - ) { - return styles.currentDate; - } - return ''; - }; - - render() { - const { rangePickerValue, salesType, currentTabKey } = this.state; - const { chart, loading } = this.props; - const { - visitData, - visitData2, - salesData, - searchData, - offlineData, - offlineChartData, - salesTypeData, - salesTypeDataOnline, - salesTypeDataOffline, - } = chart; - let salesPieData; - if (salesType === 'all') { - salesPieData = salesTypeData; - } else { - salesPieData = salesType === 'online' ? salesTypeDataOnline : salesTypeDataOffline; - } - const menu = ( - - 操作一 - 操作二 - - ); - - const dropdownGroup = ( - - - - - - ); - - const activeKey = currentTabKey || (offlineData[0] && offlineData[0].name); - - return ( - - }> - - - - - -
    - -
    - - - - - - - - - - - - - - - - ); - } -} - -export default Analysis; diff --git a/src/pages/Dashboard/Analysis.less b/src/pages/Dashboard/Analysis.less deleted file mode 100644 index 444c5e1ff3..0000000000 --- a/src/pages/Dashboard/Analysis.less +++ /dev/null @@ -1,185 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; -@import '~@/utils/utils.less'; - -.iconGroup { - i { - margin-left: 16px; - color: @text-color-secondary; - cursor: pointer; - transition: color 0.32s; - &:hover { - color: @text-color; - } - } -} - -.rankingList { - margin: 25px 0 0; - padding: 0; - list-style: none; - li { - .clearfix(); - - display: flex; - align-items: center; - margin-top: 16px; - span { - color: @text-color; - font-size: 14px; - line-height: 22px; - } - .rankingItemNumber { - display: inline-block; - width: 20px; - height: 20px; - margin-top: 1.5px; - margin-right: 16px; - font-weight: 600; - font-size: 12px; - line-height: 20px; - text-align: center; - background-color: @background-color-base; - border-radius: 20px; - &.active { - color: #fff; - background-color: #314659; - } - } - .rankingItemTitle { - flex: 1; - margin-right: 8px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - } -} - -.salesExtra { - display: inline-block; - margin-right: 24px; - a { - margin-left: 24px; - color: @text-color; - &:hover { - color: @primary-color; - } - &.currentDate { - color: @primary-color; - } - } -} - -.salesCard { - .salesBar { - padding: 0 0 32px 32px; - } - .salesRank { - padding: 0 32px 32px 72px; - } - :global { - .ant-tabs-bar { - padding-left: 16px; - .ant-tabs-nav .ant-tabs-tab { - padding-top: 16px; - padding-bottom: 14px; - line-height: 24px; - } - } - .ant-tabs-extra-content { - padding-right: 24px; - line-height: 55px; - } - .ant-card-head { - position: relative; - } - .ant-card-head-title { - align-items: normal; - } - } -} - -.salesCardExtra { - height: inherit; -} - -.salesTypeRadio { - position: absolute; - right: 54px; - bottom: 12px; -} - -.offlineCard { - :global { - .ant-tabs-ink-bar { - bottom: auto; - } - .ant-tabs-bar { - border-bottom: none; - } - .ant-tabs-nav-container-scrolling { - padding-right: 40px; - padding-left: 40px; - } - .ant-tabs-tab-prev-icon::before { - position: relative; - left: 6px; - } - .ant-tabs-tab-next-icon::before { - position: relative; - right: 6px; - } - .ant-tabs-tab-active h4 { - color: @primary-color; - } - } -} - -.twoColLayout { - .salesCard { - height: calc(100% - 24px); - } -} - -.trendText { - margin-left: 8px; - color: @heading-color; -} - -@media screen and (max-width: @screen-lg) { - .salesExtra { - display: none; - } - - .rankingList { - li { - span:first-child { - margin-right: 8px; - } - } - } -} - -@media screen and (max-width: @screen-md) { - .rankingTitle { - margin-top: 16px; - } - - .salesCard .salesBar { - padding: 16px; - } -} - -@media screen and (max-width: @screen-sm) { - .salesExtraWrap { - display: none; - } - - .salesCard { - :global { - .ant-tabs-content { - padding-top: 30px; - } - } - } -} diff --git a/src/pages/Dashboard/IntroduceRow.js b/src/pages/Dashboard/IntroduceRow.js deleted file mode 100644 index f7e67df075..0000000000 --- a/src/pages/Dashboard/IntroduceRow.js +++ /dev/null @@ -1,152 +0,0 @@ -import React, { memo } from 'react'; -import { Row, Col, Icon, Tooltip } from 'antd'; -import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale'; -import styles from './Analysis.less'; -import { ChartCard, MiniArea, MiniBar, MiniProgress, Field } from '@/components/Charts'; -import Trend from '@/components/Trend'; -import numeral from 'numeral'; -import Yuan from '@/utils/Yuan'; - -const topColResponsiveProps = { - xs: 24, - sm: 12, - md: 12, - lg: 12, - xl: 6, - style: { marginBottom: 24 }, -}; - -const IntroduceRow = memo(({ loading, visitData }) => ( - - - } - action={ - } - > - - - } - loading={loading} - total={() => 126560} - footer={ - } - value={`¥${numeral(12423).format('0,0')}`} - /> - } - contentHeight={46} - > - - - 12% - - - - 11% - - - - - - } - action={ - } - > - - - } - total={numeral(8846).format('0,0')} - footer={ - } - value={numeral(1234).format('0,0')} - /> - } - contentHeight={46} - > - - - - - } - action={ - } - > - - - } - total={numeral(6560).format('0,0')} - footer={ - - } - value="60%" - /> - } - contentHeight={46} - > - - - - - - } - action={ - } - > - - - } - total="78%" - footer={ -
    - - - 12% - - - - 11% - -
    - } - contentHeight={46} - > - -
    - - -)); - -export default IntroduceRow; diff --git a/src/pages/Dashboard/Monitor.js b/src/pages/Dashboard/Monitor.js deleted file mode 100644 index de8035342b..0000000000 --- a/src/pages/Dashboard/Monitor.js +++ /dev/null @@ -1,244 +0,0 @@ -import React, { Component } from 'react'; -import { connect } from 'dva'; -import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale'; -import { Row, Col, Card, Tooltip } from 'antd'; -import { Pie, WaterWave, Gauge, TagCloud } from '@/components/Charts'; -import NumberInfo from '@/components/NumberInfo'; -import CountDown from '@/components/CountDown'; -import ActiveChart from '@/components/ActiveChart'; -import numeral from 'numeral'; -import GridContent from '@/components/PageHeaderWrapper/GridContent'; -import Authorized from '@/utils/Authorized'; -import styles from './Monitor.less'; - -const { Secured } = Authorized; - -const targetTime = new Date().getTime() + 3900000; - -// use permission as a parameter -const havePermissionAsync = new Promise(resolve => { - // Call resolve on behalf of passed - setTimeout(() => resolve(), 300); -}); - -@Secured(havePermissionAsync) -@connect(({ monitor, loading }) => ({ - monitor, - loading: loading.models.monitor, -})) -class Monitor extends Component { - componentDidMount() { - const { dispatch } = this.props; - dispatch({ - type: 'monitor/fetchTags', - }); - } - - render() { - const { monitor, loading } = this.props; - const { tags } = monitor; - - return ( - - -
    - - } - bordered={false} - > - - - - } - suffix="元" - total={numeral(124543233).format('0,0')} - /> - - - - } - total="92%" - /> - - - - } - total={} - /> - - - - } - suffix="元" - total={numeral(234).format('0,0')} - /> - - -
    - - } - > - map - -
    - - -
    - - } - style={{ marginBottom: 24 }} - bordered={false} - > - - - } - style={{ marginBottom: 24 }} - bodyStyle={{ textAlign: 'center' }} - bordered={false} - > - - - - - - - - } - bordered={false} - className={styles.pieCard} - > - - - - } - total="28%" - height={128} - lineWidth={2} - /> - - - - } - total="22%" - height={128} - lineWidth={2} - /> - - - - } - total="32%" - height={128} - lineWidth={2} - /> - - - - - - - } - loading={loading} - bordered={false} - bodyStyle={{ overflow: 'hidden' }} - > - - - - - - } - bodyStyle={{ textAlign: 'center', fontSize: 0 }} - bordered={false} - > - - } - percent={34} - /> - - - - - ); - } -} - -export default Monitor; diff --git a/src/pages/Dashboard/Monitor.less b/src/pages/Dashboard/Monitor.less deleted file mode 100644 index 82d727229d..0000000000 --- a/src/pages/Dashboard/Monitor.less +++ /dev/null @@ -1,23 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; -@import '~@/utils/utils.less'; - -.mapChart { - height: 452px; - padding-top: 24px; - text-align: center; - img { - display: inline-block; - max-width: 100%; - max-height: 437px; - } -} - -.pieCard :global(.pie-stat) { - font-size: 24px !important; -} - -@media screen and (max-width: @screen-lg) { - .mapChart { - height: auto; - } -} diff --git a/src/pages/Dashboard/OfflineData.js b/src/pages/Dashboard/OfflineData.js deleted file mode 100644 index 71791313d2..0000000000 --- a/src/pages/Dashboard/OfflineData.js +++ /dev/null @@ -1,65 +0,0 @@ -import React, { memo } from 'react'; -import { Card, Tabs, Row, Col } from 'antd'; -import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale'; -import styles from './Analysis.less'; -import { TimelineChart, Pie } from '@/components/Charts'; -import NumberInfo from '@/components/NumberInfo'; - -const CustomTab = ({ data, currentTabKey: currentKey }) => ( - - - - } - gap={2} - total={`${data.cvr * 100}%`} - theme={currentKey !== data.name && 'light'} - /> - - - - - -); - -const { TabPane } = Tabs; - -const OfflineData = memo( - ({ activeKey, loading, offlineData, offlineChartData, handleTabChange }) => ( - - - {offlineData.map(shop => ( - } key={shop.name}> -
    - -
    -
    - ))} -
    -
    - ) -); - -export default OfflineData; diff --git a/src/pages/Dashboard/ProportionSales.js b/src/pages/Dashboard/ProportionSales.js deleted file mode 100644 index 39771300bd..0000000000 --- a/src/pages/Dashboard/ProportionSales.js +++ /dev/null @@ -1,58 +0,0 @@ -import React, { memo } from 'react'; -import { Card, Radio } from 'antd'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import styles from './Analysis.less'; -import { Pie } from '@/components/Charts'; -import Yuan from '@/utils/Yuan'; - -const ProportionSales = memo( - ({ dropdownGroup, salesType, loading, salesPieData, handleChangeSalesType }) => ( - - } - bodyStyle={{ padding: 24 }} - extra={ -
    - {dropdownGroup} -
    - - - - - - - - - - - -
    -
    - } - style={{ marginTop: 24 }} - > -

    - -

    - } - total={() => {salesPieData.reduce((pre, now) => now.y + pre, 0)}} - data={salesPieData} - valueFormat={value => {value}} - height={270} - lineWidth={4} - style={{ padding: '8px 0' }} - /> -
    - ) -); - -export default ProportionSales; diff --git a/src/pages/Dashboard/SalesCard.js b/src/pages/Dashboard/SalesCard.js deleted file mode 100644 index ee6adf214e..0000000000 --- a/src/pages/Dashboard/SalesCard.js +++ /dev/null @@ -1,150 +0,0 @@ -import React, { memo } from 'react'; -import { Row, Col, Card, Tabs, DatePicker } from 'antd'; -import { FormattedMessage, formatMessage } from 'umi-plugin-react/locale'; -import numeral from 'numeral'; -import styles from './Analysis.less'; -import { Bar } from '@/components/Charts'; - -const { RangePicker } = DatePicker; -const { TabPane } = Tabs; - -const rankingListData = []; -for (let i = 0; i < 7; i += 1) { - rankingListData.push({ - title: formatMessage({ id: 'app.analysis.test' }, { no: i }), - total: 323234, - }); -} - -const SalesCard = memo( - ({ rangePickerValue, salesData, isActive, handleRangePickerChange, loading, selectDate }) => ( - - - } - size="large" - tabBarStyle={{ marginBottom: 24 }} - > - } - key="sales" - > - -
    -
    - - } - data={salesData} - /> -
    - -
    -
    -

    - -

    -
      - {rankingListData.map((item, i) => ( -
    • - - {i + 1} - - - {item.title} - - - {numeral(item.total).format('0,0')} - -
    • - ))} -
    -
    - - - - } - key="views" - > - -
    -
    - - } - data={salesData} - /> -
    - -
    -
    -

    - -

    -
      - {rankingListData.map((item, i) => ( -
    • - - {i + 1} - - - {item.title} - - {numeral(item.total).format('0,0')} -
    • - ))} -
    -
    - - - - - - - ) -); - -export default SalesCard; diff --git a/src/pages/Dashboard/TopSearch.js b/src/pages/Dashboard/TopSearch.js deleted file mode 100644 index bd893950d0..0000000000 --- a/src/pages/Dashboard/TopSearch.js +++ /dev/null @@ -1,111 +0,0 @@ -import React, { memo } from 'react'; -import { Row, Col, Table, Tooltip, Card, Icon } from 'antd'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import Trend from '@/components/Trend'; -import numeral from 'numeral'; -import styles from './Analysis.less'; -import NumberInfo from '@/components/NumberInfo'; -import { MiniArea } from '@/components/Charts'; - -const columns = [ - { - title: , - dataIndex: 'index', - key: 'index', - }, - { - title: ( - - ), - dataIndex: 'keyword', - key: 'keyword', - render: text => {text}, - }, - { - title: , - dataIndex: 'count', - key: 'count', - sorter: (a, b) => a.count - b.count, - className: styles.alignRight, - }, - { - title: , - dataIndex: 'range', - key: 'range', - sorter: (a, b) => a.range - b.range, - render: (text, record) => ( - - {text}% - - ), - align: 'right', - }, -]; - -const TopSearch = memo(({ loading, visitData2, searchData, dropdownGroup }) => ( - - } - extra={dropdownGroup} - style={{ marginTop: 24 }} - > - -
    - - - } - > - - - - } - gap={8} - total={numeral(12321).format('0,0')} - status="up" - subTotal={17.1} - /> - - - - - - } - > - - - - } - total={2.7} - status="down" - subTotal={26.2} - gap={8} - /> - - - -
    record.index} - size="small" - columns={columns} - dataSource={searchData} - pagination={{ - style: { marginBottom: 0 }, - pageSize: 5, - }} - /> - -)); - -export default TopSearch; diff --git a/src/pages/Dashboard/Workplace.js b/src/pages/Dashboard/Workplace.js deleted file mode 100644 index 3021c2ff08..0000000000 --- a/src/pages/Dashboard/Workplace.js +++ /dev/null @@ -1,248 +0,0 @@ -import React, { PureComponent } from 'react'; -import moment from 'moment'; -import { connect } from 'dva'; -import Link from 'umi/link'; -import { Row, Col, Card, List, Avatar } from 'antd'; -import { Radar } from '@/components/Charts'; -import EditableLinkGroup from '@/components/EditableLinkGroup'; -import PageHeaderWrapper from '@/components/PageHeaderWrapper'; - -import styles from './Workplace.less'; - -const links = [ - { - title: '操作一', - href: '', - }, - { - title: '操作二', - href: '', - }, - { - title: '操作三', - href: '', - }, - { - title: '操作四', - href: '', - }, - { - title: '操作五', - href: '', - }, - { - title: '操作六', - href: '', - }, -]; - -@connect(({ user, project, activities, chart, loading }) => ({ - currentUser: user.currentUser, - project, - activities, - chart, - currentUserLoading: loading.effects['user/fetchCurrent'], - projectLoading: loading.effects['project/fetchNotice'], - activitiesLoading: loading.effects['activities/fetchList'], -})) -class Workplace extends PureComponent { - componentDidMount() { - const { dispatch } = this.props; - dispatch({ - type: 'user/fetchCurrent', - }); - dispatch({ - type: 'project/fetchNotice', - }); - dispatch({ - type: 'activities/fetchList', - }); - dispatch({ - type: 'chart/fetch', - }); - } - - renderActivities() { - const { - activities: { list }, - } = this.props; - return list.map(item => { - const events = item.template.split(/@\{([^{}]*)\}/gi).map(key => { - if (item[key]) { - return ( - - {item[key].name} - - ); - } - return key; - }); - return ( - - } - title={ - - {item.user.name} -   - {events} - - } - description={ - - {moment(item.updatedAt).fromNow()} - - } - /> - - ); - }); - } - - render() { - const { - currentUser, - currentUserLoading, - project: { notice }, - projectLoading, - activitiesLoading, - chart: { radarData }, - } = this.props; - - const pageHeaderContent = - currentUser && Object.keys(currentUser).length ? ( -
    -
    - -
    -
    -
    - 早安, - {currentUser.name} - ,祝你开心每一天! -
    -
    - {currentUser.title} |{currentUser.group} -
    -
    -
    - ) : null; - - const extraContent = ( -
    -
    -

    项目数

    -

    56

    -
    -
    -

    团队内排名

    -

    - 8 / 24 -

    -
    -
    -

    项目访问

    -

    2,223

    -
    -
    - ); - - return ( - - -
    - 全部项目} - loading={projectLoading} - bodyStyle={{ padding: 0 }} - > - {notice.map(item => ( - - - - - {item.title} - - } - description={item.description} - /> -
    - {item.member || ''} - {item.updatedAt && ( - - {moment(item.updatedAt).fromNow()} - - )} -
    -
    -
    - ))} -
    - - -
    {this.renderActivities()}
    -
    -
    - -
    - - {}} links={links} linkElement={Link} /> - - -
    - -
    -
    - -
    - - {notice.map(item => ( -
    - - - {item.member} - - - ))} - - - - - - - ); - } -} - -export default Workplace; diff --git a/src/pages/Dashboard/Workplace.less b/src/pages/Dashboard/Workplace.less deleted file mode 100644 index b67e0b64a6..0000000000 --- a/src/pages/Dashboard/Workplace.less +++ /dev/null @@ -1,228 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; -@import '~@/utils/utils.less'; - -.activitiesList { - padding: 0 24px 8px 24px; - .username { - color: @text-color; - } - .event { - font-weight: normal; - } -} - -.pageHeaderContent { - display: flex; - .avatar { - flex: 0 1 72px; - margin-bottom: 8px; - & > span { - display: block; - width: 72px; - height: 72px; - border-radius: 72px; - } - } - .content { - position: relative; - top: 4px; - flex: 1 1 auto; - margin-left: 24px; - color: @text-color-secondary; - line-height: 22px; - .contentTitle { - margin-bottom: 12px; - color: @heading-color; - font-weight: 500; - font-size: 20px; - line-height: 28px; - } - } -} - -.extraContent { - .clearfix(); - - float: right; - white-space: nowrap; - .statItem { - position: relative; - display: inline-block; - padding: 0 32px; - > p:first-child { - margin-bottom: 4px; - color: @text-color-secondary; - font-size: @font-size-base; - line-height: 22px; - } - > p { - margin: 0; - color: @heading-color; - font-size: 30px; - line-height: 38px; - > span { - color: @text-color-secondary; - font-size: 20px; - } - } - &::after { - position: absolute; - top: 8px; - right: 0; - width: 1px; - height: 40px; - background-color: @border-color-split; - content: ''; - } - &:last-child { - padding-right: 0; - &::after { - display: none; - } - } - } -} - -.members { - a { - display: block; - height: 24px; - margin: 12px 0; - color: @text-color; - transition: all 0.3s; - .textOverflow(); - .member { - margin-left: 12px; - font-size: @font-size-base; - line-height: 24px; - vertical-align: top; - } - &:hover { - color: @primary-color; - } - } -} - -.projectList { - :global { - .ant-card-meta-description { - height: 44px; - overflow: hidden; - color: @text-color-secondary; - line-height: 22px; - } - } - .cardTitle { - font-size: 0; - a { - display: inline-block; - height: 24px; - margin-left: 12px; - color: @heading-color; - font-size: @font-size-base; - line-height: 24px; - vertical-align: top; - &:hover { - color: @primary-color; - } - } - } - .projectGrid { - width: 33.33%; - } - .projectItemContent { - display: flex; - height: 20px; - margin-top: 8px; - overflow: hidden; - font-size: 12px; - line-height: 20px; - .textOverflow(); - a { - display: inline-block; - flex: 1 1 0; - color: @text-color-secondary; - .textOverflow(); - &:hover { - color: @primary-color; - } - } - .datetime { - flex: 0 0 auto; - float: right; - color: @disabled-color; - } - } -} - -.datetime { - color: @disabled-color; -} - -@media screen and (max-width: @screen-xl) and (min-width: @screen-lg) { - .activeCard { - margin-bottom: 24px; - } - .members { - margin-bottom: 0; - } - .extraContent { - margin-left: -44px; - .statItem { - padding: 0 16px; - } - } -} - -@media screen and (max-width: @screen-lg) { - .activeCard { - margin-bottom: 24px; - } - .members { - margin-bottom: 0; - } - .extraContent { - float: none; - margin-right: 0; - .statItem { - padding: 0 16px; - text-align: left; - &::after { - display: none; - } - } - } -} - -@media screen and (max-width: @screen-md) { - .extraContent { - margin-left: -16px; - } - .projectList { - .projectGrid { - width: 50%; - } - } -} - -@media screen and (max-width: @screen-sm) { - .pageHeaderContent { - display: block; - .content { - margin-left: 0; - } - } - .extraContent { - .statItem { - float: none; - } - } -} - -@media screen and (max-width: @screen-xs) { - .projectList { - .projectGrid { - width: 100%; - } - } -} diff --git a/src/pages/Dashboard/models/activities.js b/src/pages/Dashboard/models/activities.js deleted file mode 100644 index 4e0a11e277..0000000000 --- a/src/pages/Dashboard/models/activities.js +++ /dev/null @@ -1,28 +0,0 @@ -import { queryActivities } from '@/services/api'; - -export default { - namespace: 'activities', - - state: { - list: [], - }, - - effects: { - *fetchList(_, { call, put }) { - const response = yield call(queryActivities); - yield put({ - type: 'saveList', - payload: Array.isArray(response) ? response : [], - }); - }, - }, - - reducers: { - saveList(state, action) { - return { - ...state, - list: action.payload, - }; - }, - }, -}; diff --git a/src/pages/Dashboard/models/chart.js b/src/pages/Dashboard/models/chart.js deleted file mode 100644 index 8dfe4a93f5..0000000000 --- a/src/pages/Dashboard/models/chart.js +++ /dev/null @@ -1,61 +0,0 @@ -import { fakeChartData } from '@/services/api'; - -export default { - namespace: 'chart', - - state: { - visitData: [], - visitData2: [], - salesData: [], - searchData: [], - offlineData: [], - offlineChartData: [], - salesTypeData: [], - salesTypeDataOnline: [], - salesTypeDataOffline: [], - radarData: [], - loading: false, - }, - - effects: { - *fetch(_, { call, put }) { - const response = yield call(fakeChartData); - yield put({ - type: 'save', - payload: response, - }); - }, - *fetchSalesData(_, { call, put }) { - const response = yield call(fakeChartData); - yield put({ - type: 'save', - payload: { - salesData: response.salesData, - }, - }); - }, - }, - - reducers: { - save(state, { payload }) { - return { - ...state, - ...payload, - }; - }, - clear() { - return { - visitData: [], - visitData2: [], - salesData: [], - searchData: [], - offlineData: [], - offlineChartData: [], - salesTypeData: [], - salesTypeDataOnline: [], - salesTypeDataOffline: [], - radarData: [], - }; - }, - }, -}; diff --git a/src/pages/Dashboard/models/monitor.js b/src/pages/Dashboard/models/monitor.js deleted file mode 100644 index e3e832ff8b..0000000000 --- a/src/pages/Dashboard/models/monitor.js +++ /dev/null @@ -1,28 +0,0 @@ -import { queryTags } from '@/services/api'; - -export default { - namespace: 'monitor', - - state: { - tags: [], - }, - - effects: { - *fetchTags(_, { call, put }) { - const response = yield call(queryTags); - yield put({ - type: 'saveTags', - payload: response.list, - }); - }, - }, - - reducers: { - saveTags(state, action) { - return { - ...state, - tags: action.payload, - }; - }, - }, -}; diff --git a/src/pages/Editor/GGEditor/Flow/index.js b/src/pages/Editor/GGEditor/Flow/index.js deleted file mode 100644 index 97aaf6e3cc..0000000000 --- a/src/pages/Editor/GGEditor/Flow/index.js +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; -import { Row, Col } from 'antd'; -import GGEditor, { Flow } from 'gg-editor'; -import EditorMinimap from '../components/EditorMinimap'; -import { FlowContextMenu } from '../components/EditorContextMenu'; -import { FlowToolbar } from '../components/EditorToolbar'; -import { FlowItemPanel } from '../components/EditorItemPanel'; -import { FlowDetailPanel } from '../components/EditorDetailPanel'; -import styles from './index.less'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import PageHeaderWrapper from '@/components/PageHeaderWrapper'; - -GGEditor.setTrackable(false); - -const FlowPage = () => { - return ( - } - content={} - > - - - - - - - - - - - - - - - - - - - - - - ); -}; - -export default FlowPage; diff --git a/src/pages/Editor/GGEditor/Flow/index.less b/src/pages/Editor/GGEditor/Flow/index.less deleted file mode 100644 index aeffa8293b..0000000000 --- a/src/pages/Editor/GGEditor/Flow/index.less +++ /dev/null @@ -1,41 +0,0 @@ -.editor { - display: flex; - flex: 1; - flex-direction: column; - width: 100%; - height: calc(100vh - 250px); - background: #fff; -} - -.editorHd { - padding: 8px; - border: 1px solid #e6e9ed; -} - -.editorBd { - flex: 1; -} - -.editorSidebar, -.editorContent { - display: flex; - flex-direction: column; -} - -.editorSidebar { - background: #fafafa; - - &:first-child { - border-right: 1px solid #e6e9ed; - } - - &:last-child { - border-left: 1px solid #e6e9ed; - } -} - -.flow, -.mind, -.koni { - flex: 1; -} diff --git a/src/pages/Editor/GGEditor/Koni/index.js b/src/pages/Editor/GGEditor/Koni/index.js deleted file mode 100644 index 2ae34ca1f7..0000000000 --- a/src/pages/Editor/GGEditor/Koni/index.js +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; -import { Row, Col } from 'antd'; -import GGEditor, { Koni } from 'gg-editor'; -import EditorMinimap from '../components/EditorMinimap'; -import { KoniContextMenu } from '../components/EditorContextMenu'; -import { KoniToolbar } from '../components/EditorToolbar'; -import { KoniItemPanel } from '../components/EditorItemPanel'; -import { KoniDetailPanel } from '../components/EditorDetailPanel'; -import KoniCustomNode from './shape/nodes/KoniCustomNode'; -import styles from '../Flow/index.less'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import PageHeaderWrapper from '@/components/PageHeaderWrapper'; - -GGEditor.setTrackable(false); - -const KoniPage = () => { - return ( - } - content={} - > - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -export default KoniPage; diff --git a/src/pages/Editor/GGEditor/Koni/shape/nodes/KoniCustomNode.js b/src/pages/Editor/GGEditor/Koni/shape/nodes/KoniCustomNode.js deleted file mode 100644 index 4c13bb4f42..0000000000 --- a/src/pages/Editor/GGEditor/Koni/shape/nodes/KoniCustomNode.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import { RegisterNode } from 'gg-editor'; - -class KoniCustomNode extends React.Component { - render() { - const config = { - draw(item) { - const keyShape = this.drawKeyShape(item); - - // draw label - this.drawLabel(item); - - // draw image - const group = item.getGraphicGroup(); - const model = item.getModel(); - - group.addShape('image', { - attrs: { - x: -7, - y: -7, - img: model.icon, - }, - }); - - return keyShape; - }, - }; - - return ; - } -} - -export default KoniCustomNode; diff --git a/src/pages/Editor/GGEditor/Mind/index.js b/src/pages/Editor/GGEditor/Mind/index.js deleted file mode 100644 index 4e078f60f5..0000000000 --- a/src/pages/Editor/GGEditor/Mind/index.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import { Row, Col } from 'antd'; -import GGEditor, { Mind } from 'gg-editor'; -import EditorMinimap from '../components/EditorMinimap'; -import { MindContextMenu } from '../components/EditorContextMenu'; -import { MindToolbar } from '../components/EditorToolbar'; -import { MindDetailPanel } from '../components/EditorDetailPanel'; -import data from '../mock/worldCup2018.json'; -import styles from '../Flow/index.less'; -import { FormattedMessage } from 'umi-plugin-react/locale'; -import PageHeaderWrapper from '@/components/PageHeaderWrapper'; - -GGEditor.setTrackable(false); - -const MindPage = () => { - return ( - } - content={} - > - - - - - - - - - - - - - - - - - - - ); -}; - -export default MindPage; diff --git a/src/pages/Editor/GGEditor/common/IconFont/index.js b/src/pages/Editor/GGEditor/common/IconFont/index.js deleted file mode 100644 index 3bba8d2ed7..0000000000 --- a/src/pages/Editor/GGEditor/common/IconFont/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import { Icon } from 'antd'; - -const IconFont = Icon.createFromIconfontCN({ - scriptUrl: 'https://at.alicdn.com/t/font_1101588_01zniftxm9yp.js', -}); - -export default IconFont; diff --git a/src/pages/Editor/GGEditor/components/EditorContextMenu/FlowContextMenu.js b/src/pages/Editor/GGEditor/components/EditorContextMenu/FlowContextMenu.js deleted file mode 100644 index cbb7041f20..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorContextMenu/FlowContextMenu.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { NodeMenu, EdgeMenu, GroupMenu, MultiMenu, CanvasMenu, ContextMenu } from 'gg-editor'; -import MenuItem from './MenuItem'; -import styles from './index.less'; - -const FlowContextMenu = () => { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -export default FlowContextMenu; diff --git a/src/pages/Editor/GGEditor/components/EditorContextMenu/KoniContextMenu.js b/src/pages/Editor/GGEditor/components/EditorContextMenu/KoniContextMenu.js deleted file mode 100644 index 8b049a5ee7..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorContextMenu/KoniContextMenu.js +++ /dev/null @@ -1,3 +0,0 @@ -import FlowContextMenu from './FlowContextMenu'; - -export default FlowContextMenu; diff --git a/src/pages/Editor/GGEditor/components/EditorContextMenu/MenuItem.js b/src/pages/Editor/GGEditor/components/EditorContextMenu/MenuItem.js deleted file mode 100644 index 4cbde89e1a..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorContextMenu/MenuItem.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { Command } from 'gg-editor'; -import upperFirst from 'lodash/upperFirst'; -import IconFont from '../../common/IconFont'; -import styles from './index.less'; - -const MenuItem = props => { - const { command, icon, text } = props; - - return ( - -
    - - {text || upperFirst(command)} -
    -
    - ); -}; - -export default MenuItem; diff --git a/src/pages/Editor/GGEditor/components/EditorContextMenu/MindContextMenu.js b/src/pages/Editor/GGEditor/components/EditorContextMenu/MindContextMenu.js deleted file mode 100644 index 2a9d43cd28..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorContextMenu/MindContextMenu.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { NodeMenu, CanvasMenu, ContextMenu } from 'gg-editor'; -import MenuItem from './MenuItem'; -import styles from './index.less'; - -const MindContextMenu = () => { - return ( - - - - - - - - - - - - - - ); -}; - -export default MindContextMenu; diff --git a/src/pages/Editor/GGEditor/components/EditorContextMenu/index.js b/src/pages/Editor/GGEditor/components/EditorContextMenu/index.js deleted file mode 100644 index 16fcde018f..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorContextMenu/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import FlowContextMenu from './FlowContextMenu'; -import MindContextMenu from './MindContextMenu'; -import KoniContextMenu from './KoniContextMenu'; - -export { FlowContextMenu, MindContextMenu, KoniContextMenu }; diff --git a/src/pages/Editor/GGEditor/components/EditorContextMenu/index.less b/src/pages/Editor/GGEditor/components/EditorContextMenu/index.less deleted file mode 100644 index 8a2cdae3bf..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorContextMenu/index.less +++ /dev/null @@ -1,39 +0,0 @@ -.contextMenu { - display: none; - overflow: hidden; - background: #fff; - border-radius: 4px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - - .item { - display: flex; - align-items: center; - padding: 5px 12px; - cursor: pointer; - transition: all 0.3s; - user-select: none; - - &:hover { - background: #e6f7ff; - } - - i { - margin-right: 8px; - } - } - - :global { - .disable { - :local { - .item { - color: rgba(0, 0, 0, 0.25); - cursor: auto; - - &:hover { - background: #fff; - } - } - } - } - } -} diff --git a/src/pages/Editor/GGEditor/components/EditorDetailPanel/DetailForm.js b/src/pages/Editor/GGEditor/components/EditorDetailPanel/DetailForm.js deleted file mode 100644 index 3d68011530..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorDetailPanel/DetailForm.js +++ /dev/null @@ -1,129 +0,0 @@ -import React, { Fragment } from 'react'; -import { Card, Form, Input, Select } from 'antd'; -import { withPropsAPI } from 'gg-editor'; -import upperFirst from 'lodash/upperFirst'; - -const { Item } = Form; -const { Option } = Select; - -const inlineFormItemLayout = { - labelCol: { - sm: { span: 8 }, - }, - wrapperCol: { - sm: { span: 16 }, - }, -}; - -class DetailForm extends React.Component { - get item() { - const { propsAPI } = this.props; - - return propsAPI.getSelected()[0]; - } - - handleSubmit = e => { - if (e && e.preventDefault) { - e.preventDefault(); - } - - const { form, propsAPI } = this.props; - const { getSelected, executeCommand, update } = propsAPI; - - setTimeout(() => { - form.validateFieldsAndScroll((err, values) => { - if (err) { - return; - } - - const item = getSelected()[0]; - - if (!item) { - return; - } - - executeCommand(() => { - update(item, { - ...values, - }); - }); - }); - }, 0); - }; - - renderEdgeShapeSelect = () => { - return ( - - ); - }; - - renderNodeDetail = () => { - const { form } = this.props; - const { label } = this.item.getModel(); - - return ( - - {form.getFieldDecorator('label', { - initialValue: label, - })()} - - ); - }; - - renderEdgeDetail = () => { - const { form } = this.props; - const { label = '', shape = 'flow-smooth' } = this.item.getModel(); - - return ( - - - {form.getFieldDecorator('label', { - initialValue: label, - })()} - - - {form.getFieldDecorator('shape', { - initialValue: shape, - })(this.renderEdgeShapeSelect())} - - - ); - }; - - renderGroupDetail = () => { - const { form } = this.props; - const { label = '新建分组' } = this.item.getModel(); - - return ( - - {form.getFieldDecorator('label', { - initialValue: label, - })()} - - ); - }; - - render() { - const { type } = this.props; - - if (!this.item) { - return null; - } - - return ( - -
    - {type === 'node' && this.renderNodeDetail()} - {type === 'edge' && this.renderEdgeDetail()} - {type === 'group' && this.renderGroupDetail()} - -
    - ); - } -} - -export default Form.create()(withPropsAPI(DetailForm)); diff --git a/src/pages/Editor/GGEditor/components/EditorDetailPanel/FlowDetailPanel.js b/src/pages/Editor/GGEditor/components/EditorDetailPanel/FlowDetailPanel.js deleted file mode 100644 index 8d6816186b..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorDetailPanel/FlowDetailPanel.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import { Card } from 'antd'; -import { NodePanel, EdgePanel, GroupPanel, MultiPanel, CanvasPanel, DetailPanel } from 'gg-editor'; -import DetailForm from './DetailForm'; -import styles from './index.less'; - -const FlowDetailPanel = () => { - return ( - - - - - - - - - - - - - - - - - - ); -}; - -export default FlowDetailPanel; diff --git a/src/pages/Editor/GGEditor/components/EditorDetailPanel/KoniDetailPanel.js b/src/pages/Editor/GGEditor/components/EditorDetailPanel/KoniDetailPanel.js deleted file mode 100644 index 18aea9a44f..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorDetailPanel/KoniDetailPanel.js +++ /dev/null @@ -1,3 +0,0 @@ -import FlowDetailPanel from './FlowDetailPanel'; - -export default FlowDetailPanel; diff --git a/src/pages/Editor/GGEditor/components/EditorDetailPanel/MindDetailPanel.js b/src/pages/Editor/GGEditor/components/EditorDetailPanel/MindDetailPanel.js deleted file mode 100644 index 6b4d5c9ead..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorDetailPanel/MindDetailPanel.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { Card } from 'antd'; -import { NodePanel, CanvasPanel, DetailPanel } from 'gg-editor'; -import DetailForm from './DetailForm'; -import styles from './index.less'; - -const MindDetailPanel = () => { - return ( - - - - - - - - - ); -}; - -export default MindDetailPanel; diff --git a/src/pages/Editor/GGEditor/components/EditorDetailPanel/index.js b/src/pages/Editor/GGEditor/components/EditorDetailPanel/index.js deleted file mode 100644 index 8df063eff1..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorDetailPanel/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import FlowDetailPanel from './FlowDetailPanel'; -import MindDetailPanel from './MindDetailPanel'; -import KoniDetailPanel from './KoniDetailPanel'; - -export { FlowDetailPanel, MindDetailPanel, KoniDetailPanel }; diff --git a/src/pages/Editor/GGEditor/components/EditorDetailPanel/index.less b/src/pages/Editor/GGEditor/components/EditorDetailPanel/index.less deleted file mode 100644 index 081945be43..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorDetailPanel/index.less +++ /dev/null @@ -1,10 +0,0 @@ -.detailPanel { - flex: 1; - background: #fafafa; - - :global { - .ant-card { - background: #fafafa; - } - } -} diff --git a/src/pages/Editor/GGEditor/components/EditorItemPanel/FlowItemPanel.js b/src/pages/Editor/GGEditor/components/EditorItemPanel/FlowItemPanel.js deleted file mode 100644 index e6912793d9..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorItemPanel/FlowItemPanel.js +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; -import { Card } from 'antd'; -import { ItemPanel, Item } from 'gg-editor'; -import styles from './index.less'; - -const FlowItemPanel = () => { - return ( - - - - - - - - - ); -}; - -export default FlowItemPanel; diff --git a/src/pages/Editor/GGEditor/components/EditorItemPanel/KoniItemPanel.js b/src/pages/Editor/GGEditor/components/EditorItemPanel/KoniItemPanel.js deleted file mode 100644 index 9df51f98ee..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorItemPanel/KoniItemPanel.js +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import { Card } from 'antd'; -import { ItemPanel, Item } from 'gg-editor'; -import styles from './index.less'; - -const KoniItemPanel = () => { - return ( - - - - - - - - ); -}; - -export default KoniItemPanel; diff --git a/src/pages/Editor/GGEditor/components/EditorItemPanel/index.js b/src/pages/Editor/GGEditor/components/EditorItemPanel/index.js deleted file mode 100644 index 2ba03fbb70..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorItemPanel/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import FlowItemPanel from './FlowItemPanel'; -import KoniItemPanel from './KoniItemPanel'; - -export { FlowItemPanel, KoniItemPanel }; diff --git a/src/pages/Editor/GGEditor/components/EditorItemPanel/index.less b/src/pages/Editor/GGEditor/components/EditorItemPanel/index.less deleted file mode 100644 index a7acc366d1..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorItemPanel/index.less +++ /dev/null @@ -1,20 +0,0 @@ -.itemPanel { - flex: 1; - background: #fafafa; - - :global { - .ant-card { - background: #fafafa; - } - - .ant-card-body { - display: flex; - flex-direction: column; - align-items: center; - - > div { - margin-bottom: 16px; - } - } - } -} diff --git a/src/pages/Editor/GGEditor/components/EditorMinimap/index.js b/src/pages/Editor/GGEditor/components/EditorMinimap/index.js deleted file mode 100644 index 8c86b24284..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorMinimap/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import { Card } from 'antd'; -import { Minimap } from 'gg-editor'; - -const EditorMinimap = () => { - return ( - - - - ); -}; - -export default EditorMinimap; diff --git a/src/pages/Editor/GGEditor/components/EditorToolbar/FlowToolbar.js b/src/pages/Editor/GGEditor/components/EditorToolbar/FlowToolbar.js deleted file mode 100644 index 374c1858bc..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorToolbar/FlowToolbar.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import { Divider } from 'antd'; -import { Toolbar } from 'gg-editor'; -import ToolbarButton from './ToolbarButton'; -import styles from './index.less'; - -const FlowToolbar = () => { - return ( - - - - - - - - - - - - - - - - - - - - - ); -}; - -export default FlowToolbar; diff --git a/src/pages/Editor/GGEditor/components/EditorToolbar/KoniToolbar.js b/src/pages/Editor/GGEditor/components/EditorToolbar/KoniToolbar.js deleted file mode 100644 index f222007aff..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorToolbar/KoniToolbar.js +++ /dev/null @@ -1,3 +0,0 @@ -import FlowToolbar from './FlowToolbar'; - -export default FlowToolbar; diff --git a/src/pages/Editor/GGEditor/components/EditorToolbar/MindToolbar.js b/src/pages/Editor/GGEditor/components/EditorToolbar/MindToolbar.js deleted file mode 100644 index 1c83286ac0..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorToolbar/MindToolbar.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import { Divider } from 'antd'; -import { Toolbar } from 'gg-editor'; -import ToolbarButton from './ToolbarButton'; -import styles from './index.less'; - -const FlowToolbar = () => { - return ( - - - - - - - - - - - - - - - - ); -}; - -export default FlowToolbar; diff --git a/src/pages/Editor/GGEditor/components/EditorToolbar/ToolbarButton.js b/src/pages/Editor/GGEditor/components/EditorToolbar/ToolbarButton.js deleted file mode 100644 index eb5b4ffa2f..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorToolbar/ToolbarButton.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { Tooltip } from 'antd'; -import { Command } from 'gg-editor'; -import upperFirst from 'lodash/upperFirst'; -import IconFont from '../../common/IconFont'; -import styles from './index.less'; - -const ToolbarButton = props => { - const { command, icon, text } = props; - - return ( - - - - - - ); -}; - -export default ToolbarButton; diff --git a/src/pages/Editor/GGEditor/components/EditorToolbar/index.js b/src/pages/Editor/GGEditor/components/EditorToolbar/index.js deleted file mode 100644 index ac08e3dc54..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorToolbar/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import FlowToolbar from './FlowToolbar'; -import MindToolbar from './MindToolbar'; -import KoniToolbar from './KoniToolbar'; - -export { FlowToolbar, MindToolbar, KoniToolbar }; diff --git a/src/pages/Editor/GGEditor/components/EditorToolbar/index.less b/src/pages/Editor/GGEditor/components/EditorToolbar/index.less deleted file mode 100644 index a5cca37c29..0000000000 --- a/src/pages/Editor/GGEditor/components/EditorToolbar/index.less +++ /dev/null @@ -1,39 +0,0 @@ -.toolbar { - display: flex; - align-items: center; - - :global { - .command i { - display: inline-block; - width: 27px; - height: 27px; - margin: 0 6px; - padding-top: 6px; - text-align: center; - border: 1px solid #fff; - cursor: pointer; - - &:hover { - border: 1px solid #e6e9ed; - } - } - - .disable i { - color: rgba(0, 0, 0, 0.25); - cursor: auto; - - &:hover { - border: 1px solid #fff; - } - } - } -} - -.tooltip { - :global { - .ant-tooltip-inner { - font-size: 12px; - border-radius: 0; - } - } -} diff --git a/src/pages/Editor/GGEditor/mock/worldCup2018.json b/src/pages/Editor/GGEditor/mock/worldCup2018.json deleted file mode 100644 index 44f3e63f56..0000000000 --- a/src/pages/Editor/GGEditor/mock/worldCup2018.json +++ /dev/null @@ -1,129 +0,0 @@ -{ - "roots": [ - { - "label": "法国", - "children": [ - { - "label": "克罗地亚", - "side": "left", - "children": [ - { - "label": "克罗地亚", - "children": [ - { - "label": "克罗地亚", - "children": [ - { - "label": "克罗地亚" - }, - { - "label": "丹麦" - } - ] - }, - { - "label": "俄罗斯", - "children": [ - { - "label": "俄罗斯" - }, - { - "label": "西班牙" - } - ] - } - ] - }, - { - "label": "英格兰", - "children": [ - { - "label": "英格兰", - "children": [ - { - "label": "英格兰" - }, - { - "label": "哥伦比亚" - } - ] - }, - { - "label": "瑞典", - "children": [ - { - "label": "瑞士" - }, - { - "label": "瑞典" - } - ] - } - ] - } - ] - }, - { - "label": "法国", - "side": "right", - "children": [ - { - "label": "法国", - "children": [ - { - "label": "法国", - "children": [ - { - "label": "法国" - }, - { - "label": "阿根廷" - } - ] - }, - { - "label": "乌拉圭", - "children": [ - { - "label": "乌拉圭" - }, - { - "label": "葡萄牙" - } - ] - } - ] - }, - { - "label": "比利时", - "children": [ - { - "label": "比利时", - "children": [ - { - "label": "比利时" - }, - { - "label": "日本" - } - ] - }, - { - "label": "巴西", - "children": [ - { - "label": "巴西" - }, - { - "label": "墨西哥" - } - ] - } - ] - } - ] - } - ] - } - ] -} diff --git a/src/pages/Exception/403.js b/src/pages/Exception/403.js deleted file mode 100644 index e91f9c91d4..0000000000 --- a/src/pages/Exception/403.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { formatMessage } from 'umi-plugin-react/locale'; -import Link from 'umi/link'; -import Exception from '@/components/Exception'; - -const Exception403 = () => ( - -); - -export default Exception403; diff --git a/src/pages/Exception/404.js b/src/pages/Exception/404.js deleted file mode 100644 index f21b1f89de..0000000000 --- a/src/pages/Exception/404.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { formatMessage } from 'umi-plugin-react/locale'; -import Link from 'umi/link'; -import Exception from '@/components/Exception'; - -const Exception404 = () => ( - -); - -export default Exception404; diff --git a/src/pages/Exception/500.js b/src/pages/Exception/500.js deleted file mode 100644 index 904844cd1e..0000000000 --- a/src/pages/Exception/500.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { formatMessage } from 'umi-plugin-react/locale'; -import Link from 'umi/link'; -import Exception from '@/components/Exception'; - -const Exception500 = () => ( - -); - -export default Exception500; diff --git a/src/pages/Exception/TriggerException.js b/src/pages/Exception/TriggerException.js deleted file mode 100644 index 15ace510f6..0000000000 --- a/src/pages/Exception/TriggerException.js +++ /dev/null @@ -1,50 +0,0 @@ -import React, { PureComponent } from 'react'; -import { Button, Spin, Card } from 'antd'; -import { connect } from 'dva'; -import styles from './style.less'; - -@connect(state => ({ - isloading: state.error.isloading, -})) -class TriggerException extends PureComponent { - state = { - isloading: false, - }; - - triggerError = code => { - this.setState({ - isloading: true, - }); - const { dispatch } = this.props; - dispatch({ - type: 'error/query', - payload: { - code, - }, - }); - }; - - render() { - const { isloading } = this.state; - return ( - - - - - - - - - ); - } -} - -export default TriggerException; diff --git a/src/pages/Exception/models/error.js b/src/pages/Exception/models/error.js deleted file mode 100644 index 1bfd939213..0000000000 --- a/src/pages/Exception/models/error.js +++ /dev/null @@ -1,28 +0,0 @@ -import queryError from '@/services/error'; - -export default { - namespace: 'error', - - state: { - error: '', - isloading: false, - }, - - effects: { - *query({ payload }, { call, put }) { - yield call(queryError, payload.code); - yield put({ - type: 'trigger', - payload: payload.code, - }); - }, - }, - - reducers: { - trigger(state, action) { - return { - error: action.payload, - }; - }, - }, -}; diff --git a/src/pages/Exception/style.less b/src/pages/Exception/style.less deleted file mode 100644 index 91ec7dcf52..0000000000 --- a/src/pages/Exception/style.less +++ /dev/null @@ -1,7 +0,0 @@ -.trigger { - background: 'red'; - :global(.ant-btn) { - margin-right: 8px; - margin-bottom: 12px; - } -} diff --git a/src/pages/Forms/AdvancedForm.js b/src/pages/Forms/AdvancedForm.js deleted file mode 100644 index fbd3968935..0000000000 --- a/src/pages/Forms/AdvancedForm.js +++ /dev/null @@ -1,323 +0,0 @@ -import React, { PureComponent } from 'react'; -import { - Card, - Button, - Form, - Icon, - Col, - Row, - DatePicker, - TimePicker, - Input, - Select, - Popover, -} from 'antd'; -import { connect } from 'dva'; -import FooterToolbar from '@/components/FooterToolbar'; -import PageHeaderWrapper from '@/components/PageHeaderWrapper'; -import TableForm from './TableForm'; -import styles from './style.less'; - -const { Option } = Select; -const { RangePicker } = DatePicker; - -const fieldLabels = { - name: '仓库名', - url: '仓库域名', - owner: '仓库管理员', - approver: '审批人', - dateRange: '生效日期', - type: '仓库类型', - name2: '任务名', - url2: '任务描述', - owner2: '执行人', - approver2: '责任人', - dateRange2: '生效日期', - type2: '任务类型', -}; - -const tableData = [ - { - key: '1', - workId: '00001', - name: 'John Brown', - department: 'New York No. 1 Lake Park', - }, - { - key: '2', - workId: '00002', - name: 'Jim Green', - department: 'London No. 1 Lake Park', - }, - { - key: '3', - workId: '00003', - name: 'Joe Black', - department: 'Sidney No. 1 Lake Park', - }, -]; - -@connect(({ loading }) => ({ - submitting: loading.effects['form/submitAdvancedForm'], -})) -@Form.create() -class AdvancedForm extends PureComponent { - state = { - width: '100%', - }; - - componentDidMount() { - window.addEventListener('resize', this.resizeFooterToolbar, { passive: true }); - } - - componentWillUnmount() { - window.removeEventListener('resize', this.resizeFooterToolbar); - } - - getErrorInfo = () => { - const { - form: { getFieldsError }, - } = this.props; - const errors = getFieldsError(); - const errorCount = Object.keys(errors).filter(key => errors[key]).length; - if (!errors || errorCount === 0) { - return null; - } - const scrollToField = fieldKey => { - const labelNode = document.querySelector(`label[for="${fieldKey}"]`); - if (labelNode) { - labelNode.scrollIntoView(true); - } - }; - const errorList = Object.keys(errors).map(key => { - if (!errors[key]) { - return null; - } - return ( -
  • scrollToField(key)}> - -
    {errors[key][0]}
    -
    {fieldLabels[key]}
    -
  • - ); - }); - return ( - - trigger.parentNode} - > - - - {errorCount} - - ); - }; - - resizeFooterToolbar = () => { - requestAnimationFrame(() => { - const sider = document.querySelectorAll('.ant-layout-sider')[0]; - if (sider) { - const width = `calc(100% - ${sider.style.width})`; - const { width: stateWidth } = this.state; - if (stateWidth !== width) { - this.setState({ width }); - } - } - }); - }; - - validate = () => { - const { - form: { validateFieldsAndScroll }, - dispatch, - } = this.props; - validateFieldsAndScroll((error, values) => { - if (!error) { - // submit the values - dispatch({ - type: 'form/submitAdvancedForm', - payload: values, - }); - } - }); - }; - - render() { - const { - form: { getFieldDecorator }, - submitting, - } = this.props; - const { width } = this.state; - - return ( - - -
    - -
    - - {getFieldDecorator('name', { - rules: [{ required: true, message: '请输入仓库名称' }], - })()} - - - - - {getFieldDecorator('url', { - rules: [{ required: true, message: '请选择' }], - })( - - )} - - - - - {getFieldDecorator('owner', { - rules: [{ required: true, message: '请选择管理员' }], - })( - - )} - - - - - - - {getFieldDecorator('approver', { - rules: [{ required: true, message: '请选择审批员' }], - })( - - )} - - - - - {getFieldDecorator('dateRange', { - rules: [{ required: true, message: '请选择生效日期' }], - })( - - )} - - - - - {getFieldDecorator('type', { - rules: [{ required: true, message: '请选择仓库类型' }], - })( - - )} - - - - - - -
    - -
    - - {getFieldDecorator('name2', { - rules: [{ required: true, message: '请输入' }], - })()} - - - - - {getFieldDecorator('url2', { - rules: [{ required: true, message: '请选择' }], - })()} - - - - - {getFieldDecorator('owner2', { - rules: [{ required: true, message: '请选择管理员' }], - })( - - )} - - - - - - - {getFieldDecorator('approver2', { - rules: [{ required: true, message: '请选择审批员' }], - })( - - )} - - - - - {getFieldDecorator('dateRange2', { - rules: [{ required: true, message: '请输入' }], - })( - trigger.parentNode} - /> - )} - - - - - {getFieldDecorator('type2', { - rules: [{ required: true, message: '请选择仓库类型' }], - })( - - )} - - - - - - - {getFieldDecorator('members', { - initialValue: tableData, - })()} - - - {this.getErrorInfo()} - - - - ); - } -} - -export default AdvancedForm; diff --git a/src/pages/Forms/BasicForm.js b/src/pages/Forms/BasicForm.js deleted file mode 100644 index dd86ebacc6..0000000000 --- a/src/pages/Forms/BasicForm.js +++ /dev/null @@ -1,247 +0,0 @@ -import React, { PureComponent } from 'react'; -import { connect } from 'dva'; -import { formatMessage, FormattedMessage } from 'umi-plugin-react/locale'; -import { - Form, - Input, - DatePicker, - Select, - Button, - Card, - InputNumber, - Radio, - Icon, - Tooltip, -} from 'antd'; -import PageHeaderWrapper from '@/components/PageHeaderWrapper'; -import styles from './style.less'; - -const FormItem = Form.Item; -const { Option } = Select; -const { RangePicker } = DatePicker; -const { TextArea } = Input; - -@connect(({ loading }) => ({ - submitting: loading.effects['form/submitRegularForm'], -})) -@Form.create() -class BasicForms extends PureComponent { - handleSubmit = e => { - const { dispatch, form } = this.props; - e.preventDefault(); - form.validateFieldsAndScroll((err, values) => { - if (!err) { - dispatch({ - type: 'form/submitRegularForm', - payload: values, - }); - } - }); - }; - - render() { - const { submitting } = this.props; - const { - form: { getFieldDecorator, getFieldValue }, - } = this.props; - - const formItemLayout = { - labelCol: { - xs: { span: 24 }, - sm: { span: 7 }, - }, - wrapperCol: { - xs: { span: 24 }, - sm: { span: 12 }, - md: { span: 10 }, - }, - }; - - const submitFormLayout = { - wrapperCol: { - xs: { span: 24, offset: 0 }, - sm: { span: 10, offset: 7 }, - }, - }; - - return ( - } - content={} - > - -
    - }> - {getFieldDecorator('title', { - rules: [ - { - required: true, - message: formatMessage({ id: 'validation.title.required' }), - }, - ], - })()} - - }> - {getFieldDecorator('date', { - rules: [ - { - required: true, - message: formatMessage({ id: 'validation.date.required' }), - }, - ], - })( - - )} - - }> - {getFieldDecorator('goal', { - rules: [ - { - required: true, - message: formatMessage({ id: 'validation.goal.required' }), - }, - ], - })( -