diff --git a/.editorconfig b/.editorconfig old mode 100644 new mode 100755 diff --git a/.eslintrc b/.eslintrc new file mode 100755 index 0000000..f626954 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "eslint-config-umi" +} diff --git a/.gitignore b/.gitignore index a0484eb..7d50fdf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,5 @@ -# Created by .ignore support plugin (hsz.mobi) # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. -#idea -.idea -.idea/**.* - # dependencies /node_modules /npm-debug.log* @@ -21,10 +16,3 @@ # umi .umi .umi-production - - -# 部署目录 -/dist - -# 测试覆盖率统计 -/coverage diff --git a/.prettierrc b/.prettierrc index 0cc0de6..d3698d4 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { "singleQuote": true, - "trailingComma": "es5", + "trailingComma": "all", "printWidth": 100, "overrides": [ { diff --git a/.stylelintrc.json b/.stylelintrc.json deleted file mode 100644 index 13d0a84..0000000 --- a/.stylelintrc.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": [ - "stylelint-config-standard", - "stylelint-config-css-modules", - "stylelint-config-rational-order", - "stylelint-config-prettier" - ], - "plugins": [ - "stylelint-order", - "stylelint-declaration-block-no-ignored-properties" - ], - "rules": { - "no-descending-specificity": null, - "plugin/declaration-block-no-ignored-properties": true - } -} diff --git a/config/config.ts b/config/config.ts index 24bbde3..03bd390 100644 --- a/config/config.ts +++ b/config/config.ts @@ -1,136 +1,55 @@ -// https://umijs.org/config/ -import os from 'os'; -import path from 'path'; -import { IPlugin, IConfig } from 'umi-types'; -import pxToViewPort from 'postcss-px-to-viewport'; -import defaultSettings from './defaultSettings'; +import { IConfig } from 'umi-types'; import pageRoutes from './router.config'; -const { pwa, primaryColor } = defaultSettings; -const { TEST, NODE_ENV } = process.env; -const plugins: IPlugin[] = [ - [ - 'umi-plugin-react', - { +// ref: https://umijs.org/config/ +const config: IConfig = { + treeShaking: true, + routes: pageRoutes, + plugins: [ + // ref: https://umijs.org/plugin/umi-plugin-react.html + ['umi-plugin-react', { antd: true, dva: true, - fastClick: true, - autoprefixer:'', - // hd: true, - dll: true, - hardSource: false, - locale: { - // 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', webpackChunkName: true, level: 3, }, - library: 'react', - metas: [{ charset: 'utf-8' }], - pwa: pwa - ? { - workboxPluginMode: 'InjectManifest', - workboxOptions: { - importWorkboxFrom: 'local', - }, - } - : false, - ...(!TEST && os.platform() === 'darwin' - ? { - dll: { - include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch'], - exclude: ['@babel/runtime'], - }, - hardSource: false, - } - : {}), - }, + title: 'umi-dva-antd-mobile', + dll: true, + hd: true, + locale: { + enable: true, + default: 'en-US', + }, + routes: { + exclude: [ + /models\//, + /services\//, + /model\.(t|j)sx?$/, + /service\.(t|j)sx?$/, + /components\//, + ], + }, + }], ], -]; - -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 - base: '', - publicPath: '', - history: 'hash', // 默认是 browser - plugins, define: { APP_TYPE: process.env.APP_TYPE || '', }, - treeShaking: true, - targets: { - ie: 11, - android: 5, - ios: 7, - chrome: 58, - }, - devtool: false, - // 路由配置 - routes: pageRoutes, - // Theme for antd - // https://ant.design/docs/react/customize-theme-cn - theme: { - 'primary-color': primaryColor, - }, - proxy: { - '/server/api/': { - changeOrigin: true, - pathRewrite: { '^/server': '' }, - target: 'https://preview.pro.ant.design/', - }, - '/wx/api/': { - changeOrigin: true, - pathRewrite: { '^/wx/api': '' }, - target: 'https://games.parsec.com.cn/', - }, - }, + history: 'hash', // 默认是 browser ignoreMomentLocale: true, lessLoaderOptions: { javascriptEnabled: true, }, disableRedirectHoist: true, - cssLoaderOptions: { - modules: true, - }, + outputPath: './dist', + hash: true, manifest: { basePath: '/', }, - uglifyJSOptions, - alias: { - '@': path.resolve(__dirname, 'src'), - }, - chainWebpack: config => {}, extraBabelPlugins:[ ['import', { libraryName: 'antd-mobile', style: true }] //按需加载antd-mobile样式文件 ], - extraPostCSSPlugins: [ - pxToViewPort({ - viewportWidth: 375, - viewportHeight: 667, - unitPrecision: 5, - viewportUnit: 'vw', - selectorBlackList: [], - minPixelValue: 1, - mediaQuery: false, - }), - ], -} as IConfig; +}; + +export default config; diff --git a/config/router.config.ts b/config/router.config.ts index 6d0e776..4193700 100644 --- a/config/router.config.ts +++ b/config/router.config.ts @@ -1,78 +1,12 @@ export default [ - // user - { - path: '/user', - component: '../layouts/UserLayout', - routes: [ - { path: '/user', redirect: '/user/login' }, - { path: '/user/login', component: './User/Login' }, - ], - }, - // TabBar - { - path: '/tabbar', - component: '../layouts/TabBarLayout', - routes: [ - { path: '/tabbar', redirect: '/tabbar/index' }, - { - path: '/tabbar/index', - title: 'index', - component: './tabbar/index', - iconName: 'alipay', - }, - { - path: '/tabbar/koubei', - title: 'Koubei', - component: './tabbar/Koubei', - iconName: 'koubei', - }, - { - path: '/tabbar/friend', - title: 'Friend', - component: './tabbar/Friend', - iconName: 'friend', - }, - { - path: '/tabbar/my', - title: 'My', - component: './tabbar/Koubei', - iconName: 'my', - }, - ], - }, - // H5 { path: '/', - component: '../layouts/BasicLayout', - Routes: ['src/pages/Authorized'], - authority: ['user', 'admin'], + component: '../layouts/index', + // Routes: ['src/pages/Authorized'], + // authority: ['user', 'admin'], routes: [ - { path: '/', component: './home/index', title: '首页' }, - { path: '/entrance', component: './entrance/index', title: '主入口' }, - { path: '/paper/:type', component: './paper/index', title: '试题页面' }, - { path: '/result', component: './result/index', title: '结果页' }, - { - title: 'exception', - path: '/exception', - routes: [ - // Exception - { - path: '/exception/403', - title: 'not-permission', - component: './exception/403', - }, - { - path: '/exception/404', - title: 'not-find', - component: './exception/404', - }, - { - path: '/exception/500', - title: 'server-error', - component: './exception/500', - }, - ], - }, + { path: '/', component: './index', title: '首页' }, + { path: '/me', component: './me', title: '个人中心' }, { path: '/404', component: '404' }, ], }, diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index dba4680..0000000 --- a/jest.config.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - testURL: 'http://localhost:8080', - preset: 'jest-puppeteer', -}; diff --git a/mock/.gitkeep b/mock/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json index c480865..08e8f46 100644 --- a/package.json +++ b/package.json @@ -1,124 +1,61 @@ { "name": "umi-dva-antd-mobile", - "version": "1.0.0", + "version": "2.0.0", "description": "1.0.0", "private": true, "scripts": { "start": "umi dev", - "start:no-mock": "cross-env MOCK=none umi dev", "build": "umi build", "test": "umi test", - "test:component": "umi test ./src/components", - "test:all": "node ./tests/run-tests.js", - "analyze": "cross-env ANALYZE=1 umi build", - "lint": "eslint --ext .js src mock tests && npm run lint:style && npm run lint:prettier", - "lint:style": "stylelint \"src/**/*.less\" --syntax less", - "lint:fix": "eslint --fix --ext .js src mock tests && npm run lint:style", - "lint:prettier": "check-prettier lint", - "lint-staged": "lint-staged", - "lint-staged:js": "eslint --ext .js", - "tslint": "npm run tslint:fix", - "tslint:fix": "tslint --fix 'src/**/*.ts*'", - "precommit": "lint-staged", - "prettier": "node ./scripts/prettier.js" + "lint": "eslint {src,mock,tests}/**/*.{ts,tsx} --fix", + "precommit": "lint-staged" }, "dependencies": { "antd-mobile": "^2.3.1", - "babel-plugin-import": "^1.13.0", - "better-scroll": "^1.15.2", "classnames": "^2.2.6", - "dva": "^2.4.1", - "enzyme": "^3.11.0", - "hash.js": "^1.1.7", - "import-cdn-js": "^0.0.2", - "lodash": "^4.17.15", - "moment": "^2.24.0", + "dva": "^2.6.0-beta.6", "nprogress": "^0.2.0", - "nzh": "^1.0.4", - "parsec-ls": "^0.0.1", - "path-to-regexp": "^6.1.0", - "prop-types": "^15.7.2", - "qs": "^6.9.1", - "react": "^16.12.0", - "react-circle": "^1.1.1", - "react-dom": "^16.12.0", - "react-router-dom": "^5.1.2", - "react-transition-group": "^4.3.0", - "weixin-js-sdk": "^1.4.0-test" - }, - "optionalDependencies": { - "puppeteer": "^2.0.0" + "react": "^16.8.6", + "react-countup": "^4.3.3", + "react-dom": "^16.8.6", + "react-transition-group": "^4.3.0" }, "devDependencies": { - "@babel/polyfill": "^7.7.0", "@types/classnames": "^2.2.9", - "@types/lodash": "^4.14.149", - "@types/prop-types": "^15.7.3", - "@types/react": "^16.9.17", - "@types/react-dom": "^16.9.4", - "@types/react-router-dom": "^5.1.3", - "babel-eslint": "^10.0.3", - "check-prettier": "^1.0.3", - "cross-env": "^6.0.3", - "cross-port-killer": "^1.2.1", - "eslint": "^6.8.0", - "eslint-config-airbnb": "^18.0.1", - "eslint-config-prettier": "^6.9.0", - "eslint-config-umi": "^1.6.0", - "eslint-plugin-babel": "^5.3.0", - "eslint-plugin-compat": "^3.3.0", - "eslint-plugin-flowtype": "^4.5.3", - "eslint-plugin-import": "^2.19.1", - "eslint-plugin-jsx-a11y": "^6.2.3", - "eslint-plugin-markdown": "^1.0.1", - "eslint-plugin-react": "^7.17.0", - "eslint-plugin-react-hooks": "^2.3.0", - "husky": "^3.1.0", - "jest-puppeteer": "^4.4.0", - "lint-staged": "^9.5.0", - "mockjs": "^1.1.0", - "postcss-px-to-viewport": "^1.1.1", - "prettier": "^1.19.1", - "slash2": "^2.0.0", - "stylelint": "^12.0.1", - "stylelint-config-prettier": "^8.0.0", - "stylelint-config-standard": "^19.0.0", - "tslint": "^5.20.1", - "tslint-config-prettier": "^1.18.0", - "tslint-eslint-rules": "^5.4.0", - "tslint-react": "^4.1.0", - "uglifyjs-webpack-plugin": "^2.2.0", - "umi": "^2.12.8", - "umi-plugin-react": "^1.14.12", - "umi-types": "^0.5.10" + "@types/jest": "^23.3.12", + "@types/nprogress": "^0.2.0", + "@types/path-to-regexp": "^1.7.0", + "@types/react": "^16.7.18", + "@types/react-countup": "^4.0.1", + "@types/react-dom": "^16.0.11", + "@types/react-test-renderer": "^16.0.3", + "@types/react-transition-group": "^4.2.4", + "babel-eslint": "^9.0.0", + "eslint": "^5.4.0", + "eslint-config-umi": "^1.4.0", + "eslint-plugin-flowtype": "^2.50.0", + "eslint-plugin-import": "^2.14.0", + "eslint-plugin-jsx-a11y": "^5.1.1", + "eslint-plugin-react": "^7.11.1", + "husky": "^0.14.3", + "lint-staged": "^7.2.2", + "path-to-regexp": "^6.1.0", + "react-test-renderer": "^16.7.0", + "umi": "^2.9.0", + "umi-plugin-react": "^1.8.0", + "umi-types": "^0.3.0" }, "lint-staged": { - "**/*.{js,ts,tsx,md,json,jsx,less}": [ - "node ./scripts/lint-prettier.js", + "*.{ts,tsx}": [ + "eslint --fix", "git add" ], - "**/*.{js,jsx}": "npm run lint-staged:js", - "**/*.{ts,tsx}": "npm run lint-staged:ts", - "**/*.less": "stylelint --syntax less" + "*.{js,jsx}": [ + "eslint --fix", + "git add" + ] }, - "browserslist": [ - "> 1%", - "last 2 versions", - "not ie <= 10" - ], "engines": { "node": ">=8.0.0" - }, - "checkFiles": [ - "src/**/*.js*", - "src/**/*.ts*", - "src/**/*.less", - "config/**/*.js*", - "scripts/**/*.js" - ], - "husky": { - "hooks": { - "pre-commit": "npm run lint-staged" - } } } diff --git a/scripts/getPrettierFiles.js b/scripts/getPrettierFiles.js deleted file mode 100644 index 2b01a8e..0000000 --- a/scripts/getPrettierFiles.js +++ /dev/null @@ -1,21 +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/**'] }); - files = files.concat(jsFiles); - files = files.concat(tsFiles); - files = files.concat(configFiles); - files = files.concat(scriptFiles); - files = files.concat(lessFiles); - if (!files.length) { - return; - } - return files; -}; - -module.exports = getPrettierFiles; diff --git a/scripts/lint-prettier.js b/scripts/lint-prettier.js deleted file mode 100644 index 693bb7e..0000000 --- a/scripts/lint-prettier.js +++ /dev/null @@ -1,52 +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; - console.log(e); - }) - .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 bb2198c..0000000 --- a/scripts/prettier.js +++ /dev/null @@ -1,47 +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 chalk = require('chalk'); - -const getPrettierFiles = require('./getPrettierFiles'); - -const prettierConfigPath = require.resolve('../.prettierrc'); - -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/src/app.ts b/src/app.ts new file mode 100644 index 0000000..cd66ece --- /dev/null +++ b/src/app.ts @@ -0,0 +1,8 @@ +export const dva = { + config: { + onError(err: ErrorEvent) { + err.preventDefault(); + console.error(err.message); + }, + }, +}; diff --git a/src/assets/h5/avatar.png b/src/assets/h5/avatar.png deleted file mode 100644 index ff45b76..0000000 Binary files a/src/assets/h5/avatar.png and /dev/null differ diff --git a/src/assets/h5/bg-index.jpg b/src/assets/h5/bg-index.jpg deleted file mode 100644 index b581789..0000000 Binary files a/src/assets/h5/bg-index.jpg and /dev/null differ diff --git a/src/assets/h5/empty.svg b/src/assets/h5/empty.svg deleted file mode 100644 index 10456e2..0000000 --- a/src/assets/h5/empty.svg +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/h5/fail.jpg b/src/assets/h5/fail.jpg deleted file mode 100644 index 7bdcf12..0000000 Binary files a/src/assets/h5/fail.jpg and /dev/null differ diff --git a/src/assets/h5/i-choose.svg b/src/assets/h5/i-choose.svg deleted file mode 100644 index cd6eb4b..0000000 --- a/src/assets/h5/i-choose.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/assets/h5/i-wrong.svg b/src/assets/h5/i-wrong.svg deleted file mode 100644 index 6d939ee..0000000 --- a/src/assets/h5/i-wrong.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/assets/h5/pass.jpg b/src/assets/h5/pass.jpg deleted file mode 100644 index 9a85e49..0000000 Binary files a/src/assets/h5/pass.jpg and /dev/null differ diff --git a/src/assets/tarbar/alipay-un.svg b/src/assets/tarbar/alipay-un.svg deleted file mode 100644 index 70f8158..0000000 --- a/src/assets/tarbar/alipay-un.svg +++ /dev/null @@ -1 +0,0 @@ -支付宝 \ No newline at end of file diff --git a/src/assets/tarbar/alipay.svg b/src/assets/tarbar/alipay.svg deleted file mode 100644 index dfd8c38..0000000 --- a/src/assets/tarbar/alipay.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - 支付宝 选中 - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/src/assets/tarbar/friend-un.svg b/src/assets/tarbar/friend-un.svg deleted file mode 100644 index ddfaddc..0000000 --- a/src/assets/tarbar/friend-un.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - 朋友 - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/src/assets/tarbar/friend.svg b/src/assets/tarbar/friend.svg deleted file mode 100644 index 7371fee..0000000 --- a/src/assets/tarbar/friend.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - 朋友按下 - Created with Sketch. - - - - - - - - \ No newline at end of file diff --git a/src/assets/tarbar/koubei-un.svg b/src/assets/tarbar/koubei-un.svg deleted file mode 100644 index b61ddcd..0000000 --- a/src/assets/tarbar/koubei-un.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/assets/tarbar/koubei.svg b/src/assets/tarbar/koubei.svg deleted file mode 100644 index 7c1b7b8..0000000 --- a/src/assets/tarbar/koubei.svg +++ /dev/null @@ -1 +0,0 @@ -口碑 diff --git a/src/assets/tarbar/my-un.svg b/src/assets/tarbar/my-un.svg deleted file mode 100644 index f39abb2..0000000 --- a/src/assets/tarbar/my-un.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - 财富 - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/assets/tarbar/my.svg b/src/assets/tarbar/my.svg deleted file mode 100644 index ba166dd..0000000 --- a/src/assets/tarbar/my.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - 财富按下 - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/assets/yay.jpg b/src/assets/yay.jpg new file mode 100644 index 0000000..bec74e2 Binary files /dev/null and b/src/assets/yay.jpg differ diff --git a/src/components/Authorized/Authorized.js b/src/components/Authorized/Authorized.js deleted file mode 100644 index 75d57b8..0000000 --- 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/AuthorizedRoute.d.ts b/src/components/Authorized/AuthorizedRoute.d.ts deleted file mode 100644 index 41cd993..0000000 --- a/src/components/Authorized/AuthorizedRoute.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from 'react'; -// eslint-disable-next-line import/no-extraneous-dependencies -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 class AuthorizedRoute extends React.Component {} diff --git a/src/components/Authorized/AuthorizedRoute.js b/src/components/Authorized/AuthorizedRoute.js deleted file mode 100644 index 39c6a66..0000000 --- a/src/components/Authorized/AuthorizedRoute.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { Route, Redirect } from 'react-router-dom'; -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/CheckPermissions.js b/src/components/Authorized/CheckPermissions.js deleted file mode 100644 index ba83f5b..0000000 --- a/src/components/Authorized/CheckPermissions.js +++ /dev/null @@ -1,88 +0,0 @@ -import React from 'react'; -import PromiseRender from './PromiseRender'; -import { CURRENT } from './renderAuthorize'; - -function isPromise(obj) { - return ( - !!obj && - (typeof obj === 'object' || typeof obj === 'function') && - typeof obj.then === 'function' - ); -} - -/** - * 通用权限检查方法 - * Common check permissions method - * @param { 权限判定 Permission judgment type string |array | Promise | Function } authority - * @param { 你的权限 Your permission description type:string} currentAuthority - * @param { 通过的组件 Passing components } target - * @param { 未通过的组件 no pass components } Exception - */ -const checkPermissions = (authority, currentAuthority, target, Exception) => { - // 没有判定权限.默认查看所有 - // Retirement authority, return target; - if (!authority) { - return target; - } - // 数组处理 - if (Array.isArray(authority)) { - if (authority.indexOf(currentAuthority) >= 0) { - return target; - } - if (Array.isArray(currentAuthority)) { - for (let i = 0; i < currentAuthority.length; i += 1) { - const element = currentAuthority[i]; - if (authority.indexOf(element) >= 0) { - return target; - } - } - } - return Exception; - } - - // string 处理 - if (typeof authority === 'string') { - if (authority === currentAuthority) { - return target; - } - if (Array.isArray(currentAuthority)) { - for (let i = 0; i < currentAuthority.length; i += 1) { - const element = currentAuthority[i]; - if (authority === element) { - return target; - } - } - } - return Exception; - } - - // Promise 处理 - if (isPromise(authority)) { - return ; - } - - // Function 处理 - if (typeof authority === 'function') { - try { - const bool = authority(currentAuthority); - // 函数执行后返回值是 Promise - if (isPromise(bool)) { - return ; - } - if (bool) { - return target; - } - return Exception; - } catch (error) { - throw error; - } - } - throw new Error('unsupported parameters'); -}; - -export { checkPermissions }; - -const check = (authority, target, Exception) => - checkPermissions(authority, CURRENT, target, Exception); - -export default check; diff --git a/src/components/Authorized/CheckPermissions.test.js b/src/components/Authorized/CheckPermissions.test.js deleted file mode 100644 index 3988d85..0000000 --- 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/PromiseRender.js b/src/components/Authorized/PromiseRender.js deleted file mode 100644 index 86ab0ee..0000000 --- a/src/components/Authorized/PromiseRender.js +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react'; -import { ActivityIndicator } from 'antd-mobile'; - -export default class PromiseRender extends React.PureComponent { - state = { - component: null, - }; - - componentDidMount() { - this.setRenderComponent(this.props); - } - - componentDidUpdate(nextProps) { - // new Props enter - this.setRenderComponent(nextProps); - } - - // set render Component : ok or error - setRenderComponent(props) { - const ok = this.checkIsInstantiation(props.ok); - const error = this.checkIsInstantiation(props.error); - props.promise - .then(() => { - this.setState({ - component: ok, - }); - }) - .catch(() => { - this.setState({ - component: error, - }); - }); - } - - // Determine whether the incoming component has been instantiated - // AuthorizedRoute is already instantiated - // Authorized render is already instantiated, children is no instantiated - // Secured is not instantiated - checkIsInstantiation = target => { - if (!React.isValidElement(target)) { - return target; - } - return () => target; - }; - - render() { - const { component: Component } = this.state; - const { ok, error, promise, ...rest } = this.props; - return Component ? ( - - ) : ( -
- -
- ); - } -} diff --git a/src/components/Authorized/Secured.js b/src/components/Authorized/Secured.js deleted file mode 100644 index c935183..0000000 --- a/src/components/Authorized/Secured.js +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react'; -import Exception from '../Exception'; -import CheckPermissions from './CheckPermissions'; -/** - * 默认不能访问任何页面 - * default is "NULL" - */ -const Exception403 = () => ; - -// Determine whether the incoming component has been instantiated -// AuthorizedRoute is already instantiated -// Authorized render is already instantiated, children is no instantiated -// Secured is not instantiated -const checkIsInstantiation = target => { - if (!React.isValidElement(target)) { - return target; - } - return () => target; -}; - -/** - * 用于判断是否拥有权限访问此view权限 - * authority 支持传入 string, function:()=>boolean|Promise - * e.g. 'user' 只有user用户能访问 - * e.g. 'user,admin' user和 admin 都能访问 - * e.g. ()=>boolean 返回true能访问,返回false不能访问 - * e.g. Promise then 能访问 catch不能访问 - * e.g. authority support incoming string, function: () => boolean | Promise - * e.g. 'user' only user user can access - * e.g. 'user, admin' user and admin can access - * e.g. () => boolean true to be able to visit, return false can not be accessed - * e.g. Promise then can not access the visit to catch - * @param {string | function | Promise} authority - * @param {ReactNode} error 非必需参数 - */ -const authorize = (authority, error) => { - /** - * conversion into a class - * 防止传入字符串时找不到staticContext造成报错 - * String parameters can cause staticContext not found error - */ - let classError = false; - if (error) { - classError = () => error; - } - if (!authority) { - throw new Error('authority is required'); - } - return function decideAuthority(target) { - const component = CheckPermissions(authority, target, classError || Exception403); - return checkIsInstantiation(component); - }; -}; - -export default authorize; diff --git a/src/components/Authorized/demo/AuthorizedArray.md b/src/components/Authorized/demo/AuthorizedArray.md deleted file mode 100644 index 46eaf76..0000000 --- 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 8ad8b91..0000000 --- a/src/components/Authorized/demo/AuthorizedFunction.md +++ /dev/null @@ -1,31 +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 a5f12f2..0000000 --- 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 1e9537a..0000000 --- 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() { - ; - } -} -ReactDOM.render( -
- -
, - mountNode, -); -``` diff --git a/src/components/Authorized/index.d.ts b/src/components/Authorized/index.d.ts deleted file mode 100644 index b3e2f56..0000000 --- a/src/components/Authorized/index.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as 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.js b/src/components/Authorized/index.js deleted file mode 100644 index 22ac664..0000000 --- a/src/components/Authorized/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import Authorized from './Authorized'; -import AuthorizedRoute from './AuthorizedRoute'; -import Secured from './Secured'; -import check from './CheckPermissions'; -import renderAuthorize from './renderAuthorize'; - -Authorized.Secured = Secured; -Authorized.AuthorizedRoute = AuthorizedRoute; -Authorized.check = check; - -export default renderAuthorize(Authorized); diff --git a/src/components/Authorized/index.md b/src/components/Authorized/index.md deleted file mode 100644 index f3b2f80..0000000 --- a/src/components/Authorized/index.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: - en-US: Authorized - zh-CN: 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/renderAuthorize.js b/src/components/Authorized/renderAuthorize.js deleted file mode 100644 index be373d9..0000000 --- a/src/components/Authorized/renderAuthorize.js +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-disable import/no-mutable-exports */ -let CURRENT = 'NULL'; -/** - * use authority or getAuthority - * @param {string|()=>String} currentAuthority - */ -const renderAuthorize = Authorized => currentAuthority => { - if (currentAuthority) { - if (typeof currentAuthority === 'function') { - CURRENT = currentAuthority(); - } - if ( - Object.prototype.toString.call(currentAuthority) === '[object String]' || - Array.isArray(currentAuthority) - ) { - CURRENT = currentAuthority; - } - } else { - CURRENT = 'NULL'; - } - return Authorized; -}; - -export { CURRENT }; -export default Authorized => renderAuthorize(Authorized); diff --git a/src/components/Exception/index.tsx b/src/components/Exception/index.tsx index 2ae997e..ca2bc02 100644 --- a/src/components/Exception/index.tsx +++ b/src/components/Exception/index.tsx @@ -1,12 +1,13 @@ -import { Button } from 'antd'; -import classNames from 'classnames'; -import React, { createElement } from 'react'; -import config from './typeConfig'; +import { Button } from "antd"; +import classNames from "classnames"; +import React, { createElement } from "react"; +import config from "./typeConfig"; + +const styles = require("./index.less"); -const styles = require('./index.less'); export interface IExceptionProps { - type?: '403' | '404' | '500'; + type?: "403" | "404" | "500"; title?: React.ReactNode; desc?: React.ReactNode; img?: string; @@ -20,11 +21,11 @@ export interface IExceptionProps { class Exception extends React.PureComponent { public static defaultProps = { - backText: 'back to home', - redirect: '/', + backText: "back to paper", + redirect: "/" }; - constructor(props) { + constructor(props: Readonly) { super(props); this.state = {}; } @@ -33,25 +34,25 @@ class Exception extends React.PureComponent { const { className, backText, - linkElement = 'a', - type, + linkElement = "a", + type = '404', title, desc, img, actions, - redirect, + redirect = '', ...rest } = this.props; - const pageType = type in config ? type : '404'; + const pageType = type in config ? type : "404"; const clsString = classNames(styles.exception, className); const createElementProps: { - key: string; + key: string, to: string; - href: string; + href: string } = { - key: 'back-btn', + key: "back-btn", to: redirect, - href: redirect, + href: redirect }; return (

@@ -66,11 +67,11 @@ class Exception extends React.PureComponent {
{desc || config[pageType].desc}
{actions || - createElement( - linkElement, - createElementProps, - - )} + createElement( + linkElement, + createElementProps, + + )}
diff --git a/src/components/Exception/typeConfig.tsx b/src/components/Exception/typeConfig.tsx index b6e1ee5..b2dc9c6 100644 --- a/src/components/Exception/typeConfig.tsx +++ b/src/components/Exception/typeConfig.tsx @@ -1,19 +1,19 @@ const config = { - 403: { - img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg', - title: '403', - desc: '抱歉,你无权访问该页面', + '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: '抱歉,服务器出错了', + '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/PageLoading/index.tsx b/src/components/PageLoading/index.tsx index 00a923f..fc0045b 100644 --- a/src/components/PageLoading/index.tsx +++ b/src/components/PageLoading/index.tsx @@ -8,7 +8,7 @@ export default () => ( top: '50%', left: '50%', transform: 'translate(-50%, -50%)', - width: '100px', + width: '200px', height: '100px', }} > @@ -21,7 +21,7 @@ export default () => ( }} > - 加载中... + 加载中... ); diff --git a/src/components/TabBarMenu/index.less b/src/components/TabBarMenu/index.less deleted file mode 100644 index c52a552..0000000 --- a/src/components/TabBarMenu/index.less +++ /dev/null @@ -1,2 +0,0 @@ -.tabBarMenu { -} diff --git a/src/components/TabBarMenu/index.tsx b/src/components/TabBarMenu/index.tsx deleted file mode 100644 index 945fc5b..0000000 --- a/src/components/TabBarMenu/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import { ITabBarItemProps } from './tabBarItemProps'; - -const styles = require('./index.less'); - -export interface ITabBarMeunProps { - bars: ITabBarItemProps[]; -} - -export default class extends React.PureComponent { - constructor(props) { - super(props); - } - - public render() { - return
2
; - } -} diff --git a/src/components/TabBarMenu/tabBarItemProps.tsx b/src/components/TabBarMenu/tabBarItemProps.tsx deleted file mode 100644 index b02c5dc..0000000 --- a/src/components/TabBarMenu/tabBarItemProps.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; - -export declare type TabIcon = - | React.ReactElement - | { - uri: string; - }; - -export interface ITabBarItemProps { - badge?: string | number; - onPress?: () => void; - selected?: boolean; - icon?: TabIcon; - selectedIcon?: TabIcon; - title: string; - dot?: boolean; - prefixCls?: string; - style?: React.CSSProperties; -} diff --git a/src/global.jsx b/src/global.jsx deleted file mode 100644 index 98df16e..0000000 --- a/src/global.jsx +++ /dev/null @@ -1,71 +0,0 @@ -import { Toast, Modal } from 'antd-mobile'; -import { setAuthority } from '@/utils/authority'; -import initWx from '@/utils/wx'; -import debug from '@/utils/debug'; -// import defaultSettings from '../config/defaultSettings'; -import './global.less'; - -//const { pwa } = defaultSettings; - -setAuthority('admin'); - -function isWeixn() { - return /micromessenger/.test(navigator.userAgent.toLowerCase()); -} - -if (!isWeixn()) { - // 需要在微信端运行的时候 开启下面的注释 - // alert('请在微信客户端打开'); - // window.location.replace('#/404'); -} else { - debug().then(() => { - initWx({ - title: '分享标题', - imgUrl: '', // 分享图标 - isNeedLogin: true, - desc: '分享描述', - openid: process.env.NODE_ENV === 'development' ? 'oEgayjggrU06oORZJVeFUJ_KF1Mk' : undefined, - }); - }); -} - -// Notify user if offline now -window.addEventListener('sw.offline', () => { - Toast.offline('当前处于离线状态'); -}); - -// Pop up a prompt on the page asking the user if they want to use the latest version -window.addEventListener('sw.updated', e => { - console.log('sw.updated'); - const reloadSW = async () => { - // Check if there is sw whose state is waiting in ServiceWorkerRegistration - // https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration - const worker = e.detail && e.detail.waiting; - if (!worker) { - return Promise.resolve(); - } - // 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); - } else { - resolve(event.data); - } - }; - worker.postMessage({ type: 'skip-waiting' }, [channel.port2]); - }); - // Refresh current page to use the updated HTML and other assets after SW has skiped waiting - window.location.reload(true); - return true; - }; - Modal.alert('有新内容', '请点击“刷新”按钮或者手动刷新页面', [ - { - text: '刷新', - onPress: () => { - reloadSW(); - }, - }, - ]); -}); diff --git a/src/global.less b/src/global.less index 5e6e2fc..9485116 100644 --- a/src/global.less +++ b/src/global.less @@ -1,116 +1,7 @@ -@import '~antd-mobile/lib/style/themes/default'; -/* reset */ -html { +html, body, #root { -webkit-text-size-adjust: none; -webkit-user-select: none; -webkit-touch-callout: none; - font-family: Helvetica; -} - -body { - font-size: 12px; -} - -body, -h1, -h2, -h3, -h4, -h5, -h6, -p, -dl, -dd, -ul, -ol, -pre, -form, -input, -textarea, -th, -td, -select { - margin: 0; - padding: 0; - font-weight: normal; - text-indent: 0; -} - -a, -button, -input, -textarea, -select { - background: none; - -webkit-tap-highlight-color: rgba(255, 0, 0, 0); - outline: none; - -webkit-appearance: none; -} - -em { - font-style: normal; -} - -li { - list-style: none; -} - -a { - text-decoration: none; -} - -img { - border: none; - vertical-align: top; -} - -table { - border-collapse: collapse; -} - -textarea { - resize: none; - overflow: auto; -} - -/* end reset */ - -html, -body { - max-width: 750px; - min-width: 375px; - margin: auto; -} - -ol, -ul { - list-style: none; -} - -blockquote, -q { - quotes: none; -} - -blockquote:before, -blockquote:after, -q:before, -q:after { - content: ''; - content: none; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -/* iphonex 兼容方案 -https://aotu.io/notes/2017/11/27/iphonex/index.html */ - -html, -body, -#root { height: 100%; overflow: hidden; } @@ -139,12 +30,6 @@ body { clear: both; } -.fade-enter { - opacity: 0; - z-index: 1; -} - -.fade-enter.fade-enter-active { - opacity: 1; - transition: opacity 250ms ease-in; +[title~='站长统计'] { + display: none; } diff --git a/src/layouts/BasicLayout.jsx b/src/layouts/BasicLayout.jsx deleted file mode 100644 index 7014171..0000000 --- a/src/layouts/BasicLayout.jsx +++ /dev/null @@ -1,66 +0,0 @@ -import React, { PureComponent } from 'react'; -import NProgress from 'nprogress'; -import withRouter from 'umi/withRouter'; -import Authorized from '@/utils/Authorized'; -import { TransitionGroup, CSSTransition } from 'react-transition-group'; -import Exception403 from '@/pages/exception/403'; -import pathToRegexp from 'path-to-regexp'; -import { connect } from 'dva'; -import './index.less'; -import '@/layouts/nprogress.less'; - -NProgress.configure({ showSpinner: false }); - -let currHref = ''; - -class BasicLayout extends PureComponent { - getRouterAuthority = (pathname, routeData) => { - let routeAuthority = ['noAuthority']; - const getAuthority = (key, routes) => { - routes.map(route => { - if (route.path && pathToRegexp(route.path).test(key)) { - routeAuthority = route.authority; - } else if (route.routes) { - routeAuthority = getAuthority(key, route.routes); - } - return route; - }); - return routeAuthority; - }; - return getAuthority(pathname, routeData); - }; - - render() { - const { - children, - loading, - location: { pathname }, - route: { routes }, - } = this.props; - const routerConfig = this.getRouterAuthority(pathname, routes); - const { href } = window.location; // 浏览器地址栏中地址 - if (currHref !== href) { - // currHref 和 href 不一致时说明进行了页面跳转 - NProgress.start(); // 页面开始加载时调用 start 方法 - if (!loading.global) { - // loading.global 为 false 时表示加载完毕 - NProgress.done(); // 页面请求完毕时调用 done 方法 - currHref = href; // 将新页面的 href 值赋值给 currHref - } - } - - return ( - - -
- }> - {children} - -
-
-
- ); - } -} - -export default withRouter(connect(({ app, loading }) => ({ app, loading }))(BasicLayout)); diff --git a/src/layouts/ExceptionLayout.jsx b/src/layouts/ExceptionLayout.jsx deleted file mode 100644 index d026649..0000000 --- a/src/layouts/ExceptionLayout.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import React, { PureComponent } from 'react'; - -class Exception extends PureComponent { - render() { - const { children } = this.props; - - return
{children}
; - } -} - -export default Exception; diff --git a/src/layouts/TabBarLayout.jsx b/src/layouts/TabBarLayout.jsx deleted file mode 100644 index 86ecabb..0000000 --- a/src/layouts/TabBarLayout.jsx +++ /dev/null @@ -1,258 +0,0 @@ -import React from 'react'; -import withRouter from 'umi/withRouter'; -import { TabBar, Popover, Icon } from 'antd-mobile'; -import router from 'umi/router'; -import Authorized from '@/utils/Authorized'; -import Exception403 from '@/pages/exception/403'; -import pathToRegexp from 'path-to-regexp'; -import { connect } from 'dva'; -import styles from './TabBarLayout.less'; - -class TabBarLayout extends React.PureComponent { - state = { - visible: true, - selected: '', - }; - - /** - * 获取路由访问权限 - * @param pathname - * @param routeData - * @returns {string[]} - */ - getRouterAuthority = (pathname, routeData) => { - let routeAuthority = ['noAuthority']; - const getAuthority = (key, routes) => { - routes.map(route => { - if (route.path && pathToRegexp(route.path).test(key)) { - routeAuthority = route.authority; - } else if (route.routes) { - routeAuthority = getAuthority(key, route.routes); - } - return route; - }); - return routeAuthority; - }; - return getAuthority(pathname, routeData); - }; - - /** - * 获取 路由配置中带有 NAME 属性的路由信息 - * @param routes - */ - getTabBarItems = routes => { - if (routes && typeof routes === 'object') { - return (routes || []).filter(item => item.title !== undefined); - } - return []; - }; - - /** - * 渲染 组件 - * @param children - * @param pathname - * @param routes - * @returns {*} - */ - getChildrenContent = (children, pathname, routes) => { - const { visible } = this.state; - const tabBarItems = this.getTabBarItems(routes); - const routerConfig = this.getRouterAuthority(pathname, routes); - let tabBarItem = []; - if (tabBarItems && tabBarItems.length > 0) { - if (tabBarItems.length > 5) { - const items = []; - const moreItems = []; - tabBarItems.map((item, index) => { - if (index < 4) { - items.push({ - ...item, - }); - } else { - moreItems.push({ - ...item, - }); - } - return ''; - }); - - tabBarItem = items.map(item => ( - - } - selectedIcon={ -
- } - selected={pathname === item.path} - badge={0} - onPress={() => { - router.push(item.path); - }} - data-seed="logId" - > - }> - {children} - - - )); - const popoverItem = moreItems.map(item => ( - - } - > - {item.name} - - )); - - tabBarItem.push( - } - selectedIcon={ -
- } - selected={pathname === 'more'} - badge={0} - onPress={() => { - console.log('====='); - this.handleVisibleChange({ visible: true }); - }} - > - -
- -
-
- - ); - } else { - tabBarItem = tabBarItems.map(item => ( - - } - selectedIcon={ -
- } - selected={pathname === item.path} - badge={0} - onPress={() => { - router.push(item.path); - }} - data-seed="logId" - > - }> - {children} - - - )); - } - - return ( - - {tabBarItem} - - ); - } - router.push('/404'); - return <>; - }; - - handleVisibleChange = visible => { - this.setState({ - visible, - }); - }; - - onSelect = opt => { - console.log(opt.props.value); - this.setState({ - visible: false, - selected: opt.props.value, - }); - }; - - render() { - const { - children, - location: { pathname }, - route: { routes }, - } = this.props; - return ( -
-
{this.getChildrenContent(children, pathname, routes)}
-
- ); - } -} - -export default withRouter(connect(({ app, loading }) => ({ app, loading }))(TabBarLayout)); diff --git a/src/layouts/TabBarLayout.less b/src/layouts/TabBarLayout.less deleted file mode 100644 index 50119ab..0000000 --- a/src/layouts/TabBarLayout.less +++ /dev/null @@ -1,18 +0,0 @@ -@import '~antd-mobile/lib/style/themes/default.less'; - -.container { - display: flex; - flex-direction: column; - height: 100vh; - overflow: auto; - background: @border-color-base; - - .content { - padding: 0; - flex: 1; - - :global { - /* 样式覆盖,解决移动端滚动问题,避免容器模拟滚动,都采用body滚动,以及自己封装的滚动容器 */ - } - } -} diff --git a/src/layouts/UserLayout.jsx b/src/layouts/UserLayout.jsx deleted file mode 100644 index 25e0f38..0000000 --- a/src/layouts/UserLayout.jsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import Link from 'umi/link'; -import styles from './UserLayout.less'; -import logo from '../assets/logo.svg'; - -class UserLayout extends React.PureComponent { - // @TODO title - // getPageTitle() { - // const { routerData, location } = this.props; - // const { pathname } = location; - // let title = 'Ant Design Pro'; - // if (routerData[pathname] && routerData[pathname].name) { - // title = `${routerData[pathname].name} - Ant Design Pro`; - // } - // return title; - // } - - render() { - const { children } = this.props; - return ( - // @TODO -
-
-
-
- - logo - Ant Design - -
-
Ant Design 是西湖区最具影响力的 Web 设计规范
-
- {children} -
-
- ); - } -} - -export default UserLayout; diff --git a/src/layouts/UserLayout.less b/src/layouts/UserLayout.less deleted file mode 100644 index 5eb257a..0000000 --- a/src/layouts/UserLayout.less +++ /dev/null @@ -1,71 +0,0 @@ -@import '~antd/lib/style/themes/default.less'; - -.container { - display: flex; - flex-direction: column; - height: 100vh; - overflow: auto; - background: @layout-body-background; -} - -.lang { - text-align: right; - width: 100%; - height: 40px; - line-height: 44px; - :global(.ant-dropdown-trigger) { - margin-right: 24px; - } -} - -.content { - padding: 32px 0; - flex: 1; -} - -@media (min-width: @screen-md-min) { - .container { - background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg'); - background-repeat: no-repeat; - background-position: center 110px; - background-size: 100%; - } - - .content { - padding: 32px 0 24px 0; - } -} - -.top { - text-align: center; -} - -.header { - height: 44px; - line-height: 44px; - a { - text-decoration: none; - } -} - -.logo { - height: 44px; - vertical-align: top; - margin-right: 16px; -} - -.title { - font-size: 33px; - color: @heading-color; - font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif; - font-weight: 600; - position: relative; - top: 2px; -} - -.desc { - font-size: @font-size-base; - color: @text-color-secondary; - margin-top: 12px; - margin-bottom: 40px; -} diff --git a/src/layouts/__tests__/index.test.tsx b/src/layouts/__tests__/index.test.tsx new file mode 100644 index 0000000..7deae90 --- /dev/null +++ b/src/layouts/__tests__/index.test.tsx @@ -0,0 +1,16 @@ +import 'jest'; +import BasicLayout from '..'; +import React from 'react'; +import renderer, { ReactTestInstance, ReactTestRenderer } from 'react-test-renderer'; + +describe('Layout: BasicLayout', () => { + it('Render correctly', () => { + const wrapper: ReactTestRenderer = renderer.create(); + expect(wrapper.root.children.length).toBe(1); + const outerLayer = wrapper.root.children[0] as ReactTestInstance; + expect(outerLayer.type).toBe('div'); + const title = outerLayer.children[0] as ReactTestInstance; + expect(title.type).toBe('h1'); + expect(title.children[0]).toBe('Yay! Welcome to umi!'); + }); +}); diff --git a/src/layouts/index.less b/src/layouts/index.less index e2507d2..f8872c7 100644 --- a/src/layouts/index.less +++ b/src/layouts/index.less @@ -1,13 +1,5 @@ -@import '~antd-mobile/dist/antd-mobile.less'; -// 引入官方提供的 less 样式入口文件 -@import '../animation.less'; -:global(.fade-enter) { - opacity: 0; - z-index: 1; -} - -:global(.fade-enter.fade-enter-active) { - opacity: 1; - transition: opacity 250ms ease-in; +.normal { + font-family: Georgia, sans-serif; + text-align: center; } diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx new file mode 100644 index 0000000..232cf1f --- /dev/null +++ b/src/layouts/index.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import NProgress from 'nprogress'; +import { TransitionGroup, CSSTransition } from 'react-transition-group'; +import { connect } from 'dva'; +import { ConnectState } from './../models/connect'; +import styles from './index.less'; +import './nprogress.less'; + +NProgress.configure({ showSpinner: false }); + +let currHref = ''; + +export interface IBasicLayout { + loading: any; + [key: string]: any; +} +const BasicLayout: React.FC = props => { + const { children, loading, location: { pathname = '/' }, route: { routes }, } = props; + // TODO : 这里需要做路由鉴权 + + const { href } = window.location; // 浏览器地址栏中地址 + if (currHref !== href) { + // currHref 和 href 不一致时说明进行了页面跳转 + NProgress.start(); // 页面开始加载时调用 start 方法 + if (!loading.global) { + // loading.global 为 false 时表示加载完毕 + NProgress.done(); // 页面请求完毕时调用 done 方法 + currHref = href; // 将新页面的 href 值赋值给 currHref + } + } + return ( + + +
+
+ {children} +
+
+
+
+ ); +}; + +export default connect(({ loading }: ConnectState) => ({ + loading, +}))(BasicLayout); diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts new file mode 100644 index 0000000..c0635de --- /dev/null +++ b/src/locales/en-US.ts @@ -0,0 +1,5 @@ +export default { + 'index.home': 'home', + 'index.start': 'Getting Started', + 'index.me': 'Go to Personal Center', +} diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts new file mode 100644 index 0000000..a95081e --- /dev/null +++ b/src/locales/zh-CN.ts @@ -0,0 +1,5 @@ +export default { + 'index.home': '首页', + 'index.start': '开始使用', + 'index.me': '前往个人中心', +} diff --git a/src/models/.gitkeep b/src/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/models/connect.d.ts b/src/models/connect.d.ts index 423d047..c4f58d2 100644 --- a/src/models/connect.d.ts +++ b/src/models/connect.d.ts @@ -1,28 +1,3 @@ -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 }; @@ -31,26 +6,10 @@ export interface Loading { menu?: boolean; setting?: boolean; user?: boolean; + login?: 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.tsx b/src/models/global.tsx deleted file mode 100644 index 9e5ab73..0000000 --- a/src/models/global.tsx +++ /dev/null @@ -1,55 +0,0 @@ -// @ts-ignore -import { query } from '@/services/api'; -import { Effect } from './connect'; -import { Reducer } from 'redux'; -import { Subscription } from 'dva'; - -export interface GlobalModelState { - chapterData: any[]; -} -export interface GlobalModelType { - namespace: 'global'; - state: GlobalModelState; - effects: { - fetch: Effect; - }; - reducers: { - saveChapterData: Reducer; - }; - subscriptions: { setup: Subscription }; -} - -const GlobalModel: GlobalModelType = { - namespace: 'global', - state: { - chapterData: [], - }, - effects: { - *fetch({ payload }, { call, put }) { - const response = yield call(query, payload); - yield put({ - type: 'saveChapterData', - payload: response, - }); - }, - }, - reducers: { - saveChapterData(state, { payload }) { - return { - ...state, - ...payload, - }; - }, - }, - subscriptions: { - setup({ dispatch, history }) { - return history.listen(({ pathname, search }) => { - if (pathname === '/users') { - dispatch({ type: 'fetch', payload: search }); - } - }); - }, - }, -}; - -export default GlobalModel; diff --git a/src/models/h5.tsx b/src/models/h5.tsx deleted file mode 100644 index f82f358..0000000 --- a/src/models/h5.tsx +++ /dev/null @@ -1,132 +0,0 @@ -// @ts-ignore -import { queryChapter, queryQuestions, queryTestPapers, saveTestResult } from '@/services/h5'; -import { Toast } from 'antd-mobile'; -import { routerRedux } from 'dva/router'; -import LS from 'parsec-ls'; - -export default { - namespace: 'h5', - state: { - chapterData: [], - questions: [], - resultData: { - paperId: 0, - score: 0, - time: '00:00', - wrongTotal: 0, - isPass: false, - }, - }, - effects: { - *fetchChapter({ payload }, { call, put }) { - const response = yield call(queryChapter, payload); - yield put({ - type: 'saveChapter', - payload: response, - }); - }, - *fetchQuestions({ payload, callback }, { call, put, select }) { - const { chapterData } = yield select(state => state.global); - const response = yield call(queryQuestions, payload); - yield put({ - type: 'saveQuestionsData', - payload: { - questions: response, - chapterData, - }, - }); - if (callback) { - callback(response); - } - if (payload.type !== 'follow') { - yield put(routerRedux.replace(`/paper/${payload.type}`)); - } - }, - *fetchTestPapers({ callback }, { call, put, select }) { - Toast.loading('试卷生成中...'); - const { chapterData } = yield select(state => state.h5); - const response = yield call(queryTestPapers); - yield put({ - type: 'savePaperData', - payload: { - ...response, - chapterData, - }, - }); - Toast.hide(); - if (callback) { - callback(response, true); - } - }, - *submit({ payload, callback }, { call, put }) { - Toast.loading('提交试卷中...'); - const response = yield call(saveTestResult, payload); - yield put({ - type: 'saveResult', - payload: response.result || {}, - }); - Toast.hide(); - if (callback) { - callback(response); - } - yield put(routerRedux.replace('/result')); - }, - *startTheExam(_, { put, select }) { - const { questions, paper, chapterData } = yield select(state => state.h5); - yield put({ - type: 'savePaperData', - payload: { - questions, - paper, - chapterData, - }, - }); - yield put(routerRedux.replace(`/paper/test`)); - }, - }, - reducers: { - saveChapter(state, { payload }) { - return { - ...state, - chapterData: payload, - }; - }, - saveQuestionsData(state, { payload }) { - return { - ...state, - ...payload, - }; - }, - savePaperData(state, { payload }) { - return { - ...state, - questions: payload.questions, - paper: payload.paper, - }; - }, - saveResult(state, { payload }) { - let answers = []; - let questions = []; - if (LS.getObj('exam-test') !== null) { - const examTest = LS.getObj('exam-test'); - answers = examTest.answers || []; - questions = examTest.questions || []; - } - const wrongIds = LS.getObj('wrong_ids'); - LS.setObj('exam-test-result', { - answers, - questions, - result: { - ...payload, - wrong_ids: wrongIds, - }, - }); - LS.remove('exam-test'); - LS.remove('wrong_ids'); - return { - ...state, - resultData: payload, - }; - }, - }, -}; diff --git a/src/pages/404.tsx b/src/pages/404.tsx new file mode 100644 index 0000000..5e0c2aa --- /dev/null +++ b/src/pages/404.tsx @@ -0,0 +1,7 @@ +import React from 'react'; +import Link from 'umi/link'; +import Exception from '@/components/Exception'; + +export default () => ( + +); diff --git a/src/pages/Authorized.jsx b/src/pages/Authorized.jsx deleted file mode 100644 index cdebeee..0000000 --- a/src/pages/Authorized.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import RenderAuthorized from '@/components/Authorized'; -import { getAuthority } from '@/utils/authority'; -import Redirect from 'umi/redirect'; - -const Authority = getAuthority(); -const Authorized = RenderAuthorized(Authority); - -export default ({ children }) => ( - }> - {children} - -); diff --git a/src/pages/User/Login.tsx b/src/pages/User/Login.tsx deleted file mode 100644 index ebd3deb..0000000 --- a/src/pages/User/Login.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -export default class extends React.PureComponent { - public render() { - return

Login
; - } -} diff --git a/src/pages/__tests__/__mocks__/umi-plugin-locale.ts b/src/pages/__tests__/__mocks__/umi-plugin-locale.ts new file mode 100644 index 0000000..6816100 --- /dev/null +++ b/src/pages/__tests__/__mocks__/umi-plugin-locale.ts @@ -0,0 +1 @@ +export const formatMessage = (): string => 'Mock text'; diff --git a/src/pages/__tests__/index.test.tsx b/src/pages/__tests__/index.test.tsx new file mode 100644 index 0000000..0384872 --- /dev/null +++ b/src/pages/__tests__/index.test.tsx @@ -0,0 +1,21 @@ +import 'jest'; +import Index from '..'; +import React from 'react'; +import renderer, { ReactTestInstance, ReactTestRenderer } from 'react-test-renderer'; + +jest.mock('umi-plugin-locale'); + +describe('Page: index', () => { + it('Render correctly', () => { + const wrapper: ReactTestRenderer = renderer.create(); + expect(wrapper.root.children.length).toBe(1); + const outerLayer = wrapper.root.children[0] as ReactTestInstance; + expect(outerLayer.type).toBe('div'); + expect(outerLayer.children.length).toBe(2); + const getStartLink = outerLayer.findAllByProps({ + href: 'https://umijs.org/guide/getting-started.html', + }) as ReactTestInstance[]; + expect(getStartLink.length).toBe(1); + expect(getStartLink[0].children).toMatchObject(['Mock text']); + }); +}); diff --git a/src/pages/document.ejs b/src/pages/document.ejs deleted file mode 100644 index e3bc8cf..0000000 --- a/src/pages/document.ejs +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - umi-dva-antd-mobile - - - - - -
- - diff --git a/src/pages/entrance/index.less b/src/pages/entrance/index.less deleted file mode 100644 index 744360c..0000000 --- a/src/pages/entrance/index.less +++ /dev/null @@ -1,141 +0,0 @@ -@import '~antd-mobile/dist/antd-mobile.less'; - -.entranceBox { - height: 100%; - width: 100%; - position: relative; - padding: 15px 20px; - text-align: left; - overflow-y: scroll; - - .title { - padding-top: 30px; - font-size: 32px; - font-weight: 700; - } - - .subtitle { - font-size: 20px; - letter-spacing: 12px; - margin: 8px auto 60px; - } - - .select-item { - font-size: 14px; - color: #5a5a5a; - padding: 10px 15px; - border: 1px solid transparent; - border-radius: 6px; - box-shadow: 0 2px 16px 0 rgba(0, 0, 0, 0.2); - margin-bottom: 20px; - display: block; - outline: none; - text-align: justify; - transition: all 0.1s linear; - - &.opt-large { - padding: 20px 15px; - } - - &.opt-selected { - color: @brand-primary; - border: 1px solid @brand-primary; - } - } - - .bottom { - position: absolute; - left: 0; - right: 0; - bottom: 15px; - display: flex; - flex-direction: row; - padding: 20px 20px; - - :global { - .am-button { - flex: 1; - font-size: 14px; - font-weight: 400; - - &:first-child { - margin-right: 15px; - } - } - } - } -} - -.modal-wrap { - :global { - .am-modal-transparent { - width: 340px; - - .am-modal-content { - background-color: #f5f5f9; - } - } - } - - .modal-container { - .closeBtn { - position: absolute; - top: 15px; - right: 15px; - } - - .modal-header { - .avatar { - width: 85px; - height: 85px; - border-radius: 50%; - margin: 15px auto; - text-align: center; - line-height: 85px; - overflow: hidden; - - img { - width: 100%; - } - } - - .name-wrap { - margin-bottom: 25px; - } - } - - .modal-body { - font-size: 12px; - font-weight: 400; - - .desc-item { - width: 100%; - display: flex; - align-items: flex-start; - justify-items: flex-start; - margin: 5px 0; - - .item-label { - width: 80px; - } - - .item-value { - flex: 1; - text-align: left; - - span { - color: @brand-primary; - } - } - } - - .notice { - background: #fefcec; - color: #f76a24; - margin: 15px auto 0; - padding: 10px; - text-align: left; - } - } - } -} diff --git a/src/pages/entrance/index.tsx b/src/pages/entrance/index.tsx deleted file mode 100644 index a09574a..0000000 --- a/src/pages/entrance/index.tsx +++ /dev/null @@ -1,281 +0,0 @@ -import { Button, Icon, Modal, Picker } from 'antd-mobile'; -import classNames from 'classnames'; -import { connect } from 'dva'; -import LS from 'parsec-ls'; -import React from 'react'; -import * as theme from '@/theme'; - -const styles = require('./index.less'); - -interface IChapterData { - parentId?: string | number; - value: string | number; - label: React.ReactNode; - children?: IChapterData[]; -} - -interface IEntranceState { - selected: number; - chapterValue: []; - chapterLabel: string; - visible: boolean; -} - -interface IEntranceProps { - dispatch?: any; - loading?: boolean; - h5: { - chapterData: IChapterData[] | IChapterData[][]; - }; -} - -// @ts-ignore -@connect(({ h5, loading }) => ({ - h5, - loading: loading.models.h5, -})) -class Index extends React.Component { - constructor(props: any) { - super(props); - this.state = { - selected: -1, - chapterValue: [], - chapterLabel: '请选择章节', - visible: false, - }; - } - - public render() { - const { selected, chapterValue, chapterLabel, visible } = this.state; - const { - h5: { chapterData = [] }, - } = this.props; - const questionTotal = 100; - return ( -
-
网约车从业资格证
-
考题练习及模拟考试
-
{ - this.setState({ selected: 1, chapterValue: [], chapterLabel: '请选择章节' }, () => { - this.getChapterData(1); - }); - }} - > - 全国公共科目考试题库 -
-
{ - this.setState({ selected: 7, chapterValue: [], chapterLabel: '请选择章节' }, () => { - this.getChapterData(2); - }); - }} - > - 本地区域科目考试题库 -
- { - this.setState({ - selected: 0, - visible: false, - chapterValue: e, - chapterLabel: (chapterData || []).filter((x: { value: any }) => x.value === e[0])[0] - .label, - }); - }} - > -
{chapterLabel}
-
-
- - -
- { - this.setState({ - visible: false, - }); - }} - title={null} - footer={[ - { - text: '开始考试', - onPress: () => { - this.startTheExam(); - }, - style: { background: theme.primaryColor, color: '#ffffff', fontSize: 14 }, - }, - ]} - > -
-
-
{ - Modal.alert('确认放弃本次考试吗?', '', [ - { text: '放弃考试', onPress: () => this.setState({ visible: false }) }, - { text: '继续考试' }, - ]); - }} - > - -
-
- avatar -
-
- 滴滴 师傅 -
-
-
-
-
考试科目:
-
北京市出租汽车驾驶员从业资格模拟考试
-
-
-
试题数量:
-
- {questionTotal} 题 -
-
-
-
考试时间:
-
- 共 80 分钟 (公共科目 - 50 - 分钟,区域科目 - 30 - 分钟) -
-
-
-
合格标准:
-
-

- 公共科目 - 40分 - 及格,满分 - 50分; -

-

- 区域科目-理论知识 - 32分 - 及格,满分 - 40分; -

-

- 区域科目-运营实务 - 8分 - 及格,满分 - 10分; -

-

- 每题 - 1分 - ,共计 - 100题 - ,总分 - 100分; -

-
-
-
- 温馨提示:按照驾管部要求,考试不能修改答案,每做一题,系统自动计算错题数。 -
-
-
-
-
- ); - } - - /** - * 获取试题 - * @param step - */ - public getPaper = (step: number) => { - const { selected, chapterValue } = this.state; - const { dispatch } = this.props; - if (step === 2 && (selected === -1 || chapterValue.length === 0)) { - Modal.alert('请选择地区和章节', ''); - return; - } - // @ts-ignore - const sectionId = chapterValue[0]; - LS.setObj('exam-region', { chapterId: selected, sectionId }); - if (step === 2) { - // @TODO 生成考题预习 - dispatch({ - type: 'h5/fetchQuestions', - payload: { - chapterID: selected, - sectionID: sectionId, - type: 'preview', - }, - }); - } else { - // @TODO 生成考试试卷 - dispatch({ - type: 'h5/fetchTestPapers', - callback: (response: { paper: any }, modalVisible: any) => { - this.setState({ - visible: modalVisible, - }); - LS.setObj('exam-paper', response.paper); - }, - }); - } - }; - - /** - * 取得一级或二级章节列表 - */ - private getChapterData = (parentID: number) => { - const { dispatch } = this.props; - dispatch({ - type: 'h5/fetchChapter', - payload: { parentID }, - }); - }; - - /** - * 开始考试 - */ - private startTheExam = () => { - const { dispatch } = this.props; - dispatch({ - type: 'h5/startTheExam', - }); - }; -} - -export default Index; diff --git a/src/pages/exception/403.js b/src/pages/exception/403.js deleted file mode 100644 index c516b69..0000000 --- a/src/pages/exception/403.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -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 c14f6ad..0000000 --- a/src/pages/exception/404.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -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 adf39f3..0000000 --- a/src/pages/exception/500.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import Link from 'umi/link'; -import Exception from '@/components/Exception'; - -const Exception500 = () => ( - -); - -export default Exception500; diff --git a/src/pages/home/index.less b/src/pages/home/index.less deleted file mode 100644 index 85763b5..0000000 --- a/src/pages/home/index.less +++ /dev/null @@ -1,36 +0,0 @@ -.home { - width: 100%; - height: 100%; - position: relative; - .index { - width: 100%; - height: 100%; - position: relative; - background: #fff url('../../assets/h5/bg-index.jpg') 50% / contain no-repeat; - text-align: center; - - .title { - padding-top: 50px; - font-size: 32px; - font-weight: 700; - } - - .subtitle { - font-size: 20px; - letter-spacing: 12px; - text-indent: 16px; - margin-top: 18px; - } - - .btn-enter { - width: 90%; - position: absolute; - bottom: 35px; - left: 0; - right: 0; - margin: 0 auto; - font-size: 14px; - font-weight: 400; - } - } -} diff --git a/src/pages/home/index.tsx b/src/pages/home/index.tsx deleted file mode 100644 index 93b6b9b..0000000 --- a/src/pages/home/index.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Button } from 'antd-mobile'; -import React from 'react'; -import router from 'umi/router'; -import styles from './index.less'; - -export default class extends React.Component<{}, {}, any> { - constructor(props: any) { - super(props); - } - - public render = () => { - return ( -
-
-
网约车从业资格证
-
考题练习及模拟考试
- -
-
- ); - }; -} diff --git a/src/pages/index.less b/src/pages/index.less new file mode 100644 index 0000000..19b6333 --- /dev/null +++ b/src/pages/index.less @@ -0,0 +1,33 @@ + +.normal { + font-family: Georgia, sans-serif; + text-align: center; + + + .welcome { + height: 512px; + background: url(../assets/yay.jpg) no-repeat center 0; + background-size: 512px 512px; + } + + .title { + font-size: 46px; + font-weight: normal; + letter-spacing: -1px; + background: darkslateblue; + padding: .6em 0; + color: white; + margin: 0; + } + + .list { + font-size: 1.2em; + margin: 1.8em 0 0; + list-style: none; + line-height: 1.5em; + + code { + background: #f7f7f7; + } + } +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx new file mode 100755 index 0000000..0a469dd --- /dev/null +++ b/src/pages/index.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { formatMessage } from 'umi-plugin-locale'; +import {Button, NavBar, Icon} from 'antd-mobile'; +import { Link } from 'umi'; +import styles from './index.less'; + +export default function() { + return ( +
+ } + onLeftClick={() => console.log('onLeftClick')} + rightContent={[ + , + , + ]} + >{formatMessage({ id: 'index.home' })} +

Yay! Welcome to umi!

+
+ + +
+ ); +} diff --git a/src/pages/me.tsx b/src/pages/me.tsx new file mode 100644 index 0000000..2af7cbd --- /dev/null +++ b/src/pages/me.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon, NavBar } from 'antd-mobile'; +import { formatMessage } from 'umi-plugin-locale'; +import styles from '@/pages/index.less'; + + +export default function() { + return ( +
+ } + onLeftClick={() => history.back()} + >{formatMessage({id: 'index.me'})} +

{formatMessage({id: 'index.me'})}

+
+ ); +} diff --git a/src/pages/paper/index.less b/src/pages/paper/index.less deleted file mode 100644 index ed294e8..0000000 --- a/src/pages/paper/index.less +++ /dev/null @@ -1,223 +0,0 @@ -@import '~antd-mobile/dist/antd-mobile.less'; -@import '../../animation.less'; - -:global { - .am-button { - a:hover { - color: #fff; - } - } - - .am-button-ghost { - a:hover { - color: @brand-primary; - } - } -} - -.test-paper { - width: 100%; - height: 100%; - position: relative; - overflow-y: scroll; - - .top-wrap { - padding: 20px 15px 0; - min-height: calc(100vh - 115px); - - .title { - font-size: 16px; - letter-spacing: 1px; - } - - .category { - margin-top: 20px; - margin-bottom: 25px; - font-size: 22px; - font-weight: 600; - } - - .follow { - position: absolute; - right: 20px; - top: 60px; - width: 80px; - height: 30px; - - .follow-ghost { - height: 30px; - line-height: 30px; - color: @brand-primary; - font-size: 13px; - border-radius: 4px; - text-align: right; - //border: @border-width-sm solid @brand-primary; - } - - img { - width: 16px; - vertical-align: middle; - margin-right: 3px; - } - } - - .back { - display: inline-block; - font-size: 14px; - color: @brand-primary; - border: 1px solid @brand-primary; - border-radius: 4px; - padding: 6px 12px; - font-weight: 400; - position: absolute; - right: 18px; - top: 20px; - } - - .question { - .description { - //line-height: 22px; - letter-spacing: 1px; - background-color: #f2f2f2; - color: #5a5a5a; - font-size: 16px; - text-align: justify; - padding: 15px 15px; - margin-bottom: 25px; - border-radius: 4px; - position: relative; - - &:after { - content: ''; - width: 0; - height: 0; - border-style: solid; - border-width: 20px 20px 0 0; - border-color: #f2f2f2 transparent transparent transparent; - position: absolute; - bottom: -20px; - left: 20px; - } - } - - .options { - .option { - padding: 10px 8px 10px 20px; - font-size: 14px; - color: #5a5a5a; - border-radius: 4px; - box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.1); - margin-bottom: 15px; - border: 1px solid transparent; - display: block; - background-color: #fff; - outline: none; - text-align: justify; - position: relative; - transition: all 0.1s linear; - - .checkbox-input { - position: absolute; - top: 0; - left: 0; - opacity: 0; - width: 100%; - height: 100%; - z-index: 2; - border: 0 none; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - } - - &:before, - &:after { - content: ''; - width: 22px; - height: 22px; - position: absolute; - top: 0; - bottom: 0; - right: 12px; - margin: auto; - opacity: 0; - } - - &:before { - background: url('../../assets/h5/i-wrong.svg') 50%/98% no-repeat; - } - - &:after { - background: url('../../assets/h5/i-choose.svg') 50%/98% no-repeat; - } - - &.correct { - &:after { - opacity: 1; - } - } - - &.error { - &:before { - opacity: 1; - } - } - - &.opt-selected, - &.opt-selected-wrong { - color: @brand-primary; - border: 1px solid @brand-primary; - } - } - } - } - } - - .bottom { - display: flex; - flex-direction: row; - align-items: center; - padding: 20px 0; - background: #fff; - z-index: 1; - - .circle-progress { - position: relative; - width: 60px; - height: 60px; - - .progress { - transition: all 0.8s ease-out; - } - - .num { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - font-size: 14px; - color: #333; - } - } - - :global { - .am-button { - flex: 1; - font-size: 14px; - font-weight: 400; - margin: 0 15px; - } - } - } - - .empty-content { - padding: 180px 0; - text-align: center; - color: #b2b2b2; - - img { - width: 100px; - margin-bottom: 5px; - } - } -} diff --git a/src/pages/paper/index.tsx b/src/pages/paper/index.tsx deleted file mode 100644 index 49a506b..0000000 --- a/src/pages/paper/index.tsx +++ /dev/null @@ -1,399 +0,0 @@ -import { Button, Modal } from 'antd-mobile'; -import classnames from 'classnames'; -import { connect } from 'dva'; -import LS from 'parsec-ls'; -import React, { Fragment } from 'react'; -import Circle from 'react-circle'; -import router from 'umi/router'; -import * as theme from '../../theme'; - -const styles = require('./index.less'); - -interface IPaperState { - current: number; // 当前题目下标 - selected: [] | any; - answers: - | Array<{ - questionId: number; - answer: []; - }> - | any; - type: string; -} - -interface ITextPaperProps { - dispatch?: any; - h5: { - questions: Array<{ - id: number; - status: 'ONLINE' | 'OFFLINE'; - description: string; - options: string[]; - answers: number[]; - userAnswer?: number[]; - chapterID: number; - sectionID: number; - wrongTimes: number; - testTimes: number; - createAt: string; - updateAt: string; - }>; - }; -} - -@connect(({ h5, loading }) => ({ - h5, - loading: loading.models.h5, -})) -class Index extends React.PureComponent { - constructor(props) { - super(props); - this.state = { - current: 0, - selected: [], - answers: [], - type: props.match.params.type, - }; - } - - public componentDidMount() { - const { type } = this.state; - if (type === '') { - this.loadWrongQuestions(); - } - } - - /** - * 获取题型 - * @param answers - * @param options - * @returns {string} - */ - private getQuestionsType = (answers, options) => { - if (options && answers) { - if (options.length === 2 && answers.length === 1) { - return '判断题'; - } else if (options.length > 2 && answers.length > 1) { - return '多选题'; - } else { - return '单选题'; - } - } else { - return '单选题'; - } - }; - - /** - * 提交试卷答题信息 - */ - private handleTestSubmit = () => { - Modal.alert('确认提交本次考试成绩吗?', '', [ - { text: '继续考试', onPress: () => console.log('继续考试') }, - { - text: '确认交卷', - onPress: () => { - this.submitTestResult(); - }, - }, - ]); - }; - - /** - * 提交试卷结果 - * @returns {Promise} - */ - private submitTestResult = async () => { - await this.handleFilterWrongQuestionsId(); - const { dispatch } = this.props; - let answers = []; - if (LS.getObj('exam-test') !== null) { - const examTest = LS.getObj('exam-test'); - answers = examTest.answers || []; - } - - dispatch({ - type: 'h5/submit', - payload: { - paperId: LS.getObj('exam-paper').id, - answers, - }, - }); - }; - - /** - * 获取试卷中的错题 ID 信息 - */ - private handleFilterWrongQuestionsId = () => { - const { - h5: { questions = [] }, - } = this.props; - if (LS.getObj('exam-test') != null) { - const { answers = [] } = LS.getObj('exam-test'); - if (questions && questions.length > 0) { - if (answers && answers.length > 0) { - // 有用户选择的答案时 - const wrongIds = []; - answers.map(item => { - if (item && item.answer) { - const question = questions.filter(x => x.id === item.questionId)[0]; - const qanswers = question.answers.sort().join(','); - const answerStr = item.answer.sort().join(','); - if (qanswers.toString() !== answerStr.toString()) { - wrongIds.push(item.questionId); - } - } - }); - LS.setObj('wrong_ids', wrongIds); - } else { - // 用户没有选择 则错题为全部错题 - const wrongIds = []; - questions.map(item => { - wrongIds.push(item.id); - }); - LS.setObj('wrong_ids', wrongIds); - } - } - } else { - const wrongIds = []; - questions.map(item => { - wrongIds.push(item.id); - }); - LS.setObj('wrong_ids', wrongIds); - } - }; - - /** - * 渲染试题 一页一题 - * @returns {*} - */ - private getPaperContent = () => { - let { current, selected } = this.state; - const { answers, type } = this.state; - const { - h5: { questions }, - } = this.props; - const question = questions.length > 0 ? questions[current] : undefined; - const questionsType = - question !== undefined ? this.getQuestionsType(question.answers, question.options) : '--'; - return ( - -
-
驾驶员从业资格模拟考试
-
{questionsType}
-
{ - if (type === 'test') { - Modal.alert('确认提交本次考试成绩吗?', '', [ - { - text: '确认交卷', - onPress: () => { - LS.setObj('exam-test', { current, questions, answers }); - this.submitTestResult(); - }, - }, - { text: '继续考试', onPress: () => console.log('ok') }, - ]); - } - if (type === 'preview' || type === 'wrong') { - router.push('/entrance'); - } - }} - > - {type === 'test' ? `交 卷` : '返回首页'} -
-
- {question !== undefined && ( - <> -
{question.description || '--'}
-
- {question.options.map((item, index) => ( -
x === index).length > 0, - [styles['opt-selected-wrong']]: - type === 'wrong' && - question.userAnswer.filter(x => x === index).length > 0, - [styles['opt-selected']]: - type === 'test' && (selected.filter(x => x === index) || []).length > 0, - })} - > - x === index).length > 0} - className={styles['checkbox-input']} - onChange={e => { - if (questionsType === '多选题') { - if (e.target.checked) { - answers.push(index); - } else { - selected = selected.filter(x => x !== index); - } - } else if (e.target.checked) { - selected = []; - selected.push(index); - } else { - selected = selected.filter(x => x !== index); - } - this.setState({ selected }); - }} - /> - {item} -
- ))} -
- - )} -
-
-
- -
- -
- -
-
- ); - }; - - public render() { - const { - h5: { questions }, - } = this.props; - return ( -
- {questions && questions.length > 0 ? ( - this.getPaperContent() - ) : ( - -
-
模拟考试试卷
-
{ - router.push('/entrance'); - }} - > - 返回首页 -
-
- -
没有任何模拟考试试题信息
-
-
-
- )} -
- ); - } - - private loadWrongQuestions = () => { - const { dispatch } = this.props; - const examResult = LS.getObj('exam-test-result'); - let data = []; - if (examResult !== null) { - const { - result: { wrong_ids = [] }, - questions = [], - answers = [], - } = examResult; - data = wrong_ids - .map(id => ({ - ...(questions.filter(x => x.id === id)[0] || {}), - userAnswer: this.getUserSelectAnswer(answers, id), - })) - .filter(x => x !== null); - } - // 先获取一遍数据 避免 js 报错 - dispatch({ - type: 'h5/savePaperData', - payload: { - questions: data, - paper: LS.getObj('exam-paper') || {}, - }, - }); - }; - - private getUserSelectAnswer = (answers, id) => { - if (answers && answers.length > 0) { - return answers.filter(x => x.questionId === id)[0].answer; - } - return []; - }; -} - -export default Index; diff --git a/src/pages/result/index.less b/src/pages/result/index.less deleted file mode 100644 index f0264d7..0000000 --- a/src/pages/result/index.less +++ /dev/null @@ -1,158 +0,0 @@ -@import '~antd-mobile/dist/antd-mobile.less'; - -.result { - width: 100%; - height: 100vh; - padding: 30px 25px; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - - .card { - width: 100%; - box-shadow: 0 8px 26px 0 rgba(0, 0, 0, 0.1); - padding: 20px 0 46px; - font-size: 0; - - .img-wrap { - text-align: center; - - .title { - font-size: 34px; - font-weight: 600; - text-align: center; - margin: 0 auto; - } - - img { - width: 240px; - margin: 0 auto; - } - - .wording { - font-size: 22px; - letter-spacing: 3px; - text-indent: 2px; - } - - .score { - height: 42px; - line-height: 42px; - font-size: 18px; - border: 1px solid @brand-primary; - color: @brand-primary; - display: inline-block; - margin: 10px auto; - padding: 0 12px; - } - - .duration { - font-size: 14px; - height: 32px; - line-height: 32px; - margin-bottom: 26px; - } - } - - .btns { - padding: 0 20px; - - .buttonGroup { - width: 100%; - display: flex; - flex-direction: row; - - a { - flex: 1; - - &:first-child { - margin-right: 5px; - } - - &:last-child { - margin-left: 5px; - } - } - } - - a { - font-size: 14px; - font-weight: 400; - - &:hover { - color: #fff; - } - - &:first-child { - margin-bottom: 12px; - - &:hover { - color: @brand-primary; - } - } - } - } - } -} - -.modal-wrap { - :global(.am-modal-transparent) { - width: 300px; - } - - .modal-list-item { - width: 100%; - display: flex; - flex-direction: row; - border-left: 1px solid #ddd; - border-top: 1px solid #ddd; - justify-content: center; - align-items: center; - margin: 0; - padding: 0; - - &:first-child { - .modal-list-col { - color: @brand-primary !important; - } - } - - &:last-child { - border-bottom: 1px solid #ddd; - } - - .modal-list-col { - text-align: left; - font-size: 14px; - height: 35px; - line-height: 35px; - margin: 0; - padding: 0; - - &:nth-child(1) { - flex: 1; - border-right: 1px solid #ddd; - } - - &:nth-child(2) { - width: 65px; - text-align: center; - border-right: 1px solid #ddd; - color: @brand-primary; - } - - &:nth-child(3) { - width: 40px; - text-align: center; - border-right: 1px solid #ddd; - color: @error-title-color; - } - } - } -} diff --git a/src/pages/result/index.tsx b/src/pages/result/index.tsx deleted file mode 100644 index 3cbf6d0..0000000 --- a/src/pages/result/index.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { Button } from 'antd-mobile'; -import { connect } from 'dva'; -import LS from 'parsec-ls'; -import React from 'react'; -import router from 'umi/router'; - -const styles = require('./index.less'); - -interface IResultState { - resultData: { - score: number; - time: string; - isPass: boolean; - }; -} - -@connect(({ h5, loading }) => ({ - h5, - loading: loading.models.h5, -})) -class Result extends React.PureComponent { - constructor(props: any) { - super(props); - const { - h5: { - resultData: { score = 0, time = '00:00', isPass }, - }, - } = props; - this.state = { - resultData: { - score, - time, - isPass, - }, - }; - } - - public componentDidMount() { - if (LS.getObj('exam-test-result') === null) { - router.push('/'); - return; - } - const { result } = LS.getObj('exam-test-result'); - const { resultData } = this.state; - if (result) { - this.setState({ - resultData: { - ...resultData, - ...result, - }, - }); - } - } - - public render() { - const { - resultData: { score = 0, time = '00:00', isPass }, - } = this.state; - return ( -
-
-
- {this.getTitleContent(isPass)} -
科目考试成绩
-
{score || 0} 分
-
答题时长:{time || '00:00'}
-
-
- - -
-
-
- ); - } - - private getTitleContent = (isPass: boolean) => { - if (isPass) { - return ( - <> -
- 恭喜您
考试通过啦 -
- - - ); - } - return ( - <> -
- 很遗憾
您没有通过考试 -
- - - ); - }; - /** - * 查看错题 - */ - private goToWrongPage = () => { - const { dispatch } = this.props; - const examResult = LS.getObj('exam-test-result'); - let data = []; - if (examResult !== null) { - const { - result: { wrong_ids = [] }, - questions = [], - answers = [], - } = examResult; - data = wrong_ids - .map((id: any) => ({ - ...(questions.filter(x => x.id === id)[0] || {}), - userAnswer: this.getUserSelectAnswer(answers, id), - })) - .filter(x => x !== null); - } - // 先获取一遍数据 避免 js 报错 - dispatch({ - type: 'h5/savePaperData', - payload: { - questions: data, - paper: LS.getObj('exam-paper') || {}, - }, - }); - router.push('/paper/wrong'); - }; - - private getUserSelectAnswer = (answers, id) => { - if (answers && answers.length > 0) { - return answers.filter(x => x.questionId === id)[0].answer; - } - return []; - }; -} - -export default Result; diff --git a/src/pages/tabbar/Friend.tsx b/src/pages/tabbar/Friend.tsx deleted file mode 100644 index ecf057c..0000000 --- a/src/pages/tabbar/Friend.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; - -export default class extends React.PureComponent<{}, {}, any> { - public render() { - return <>{this.renderContent()}; - } - - private renderContent = () => { - return ( -
-

TabBar Friend Content

-
- ); - }; -} diff --git a/src/pages/tabbar/Koubei.tsx b/src/pages/tabbar/Koubei.tsx deleted file mode 100644 index 2de7f82..0000000 --- a/src/pages/tabbar/Koubei.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; - -export default class extends React.PureComponent { - public render() { - return <>{this.renderContent()}; - } - - private renderContent = () => { - return ( -
-

TabBar Koubei Content

-
- ); - }; -} diff --git a/src/pages/tabbar/index.tsx b/src/pages/tabbar/index.tsx deleted file mode 100644 index cc8545a..0000000 --- a/src/pages/tabbar/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; - -export default class extends React.PureComponent<{}, {}, any> { - public render() { - console.log('this.props', this.props); - return <>{this.renderContent()}; - } - - private renderContent = () => { - return ( -
-

TabBar Index Content

-
- ); - }; -} diff --git a/src/service-worker.js b/src/service-worker.js deleted file mode 100644 index daa10d3..0000000 --- a/src/service-worker.js +++ /dev/null @@ -1,63 +0,0 @@ -/* globals workbox */ -/* eslint-disable no-restricted-globals */ -workbox.core.setCacheNameDetails({ - prefix: 'antd-pro', - suffix: 'v1', -}); -// Control all opened tabs ASAP -workbox.clientsClaim(); - -/** - * Use precaching list generated by workbox in build process. - * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.precaching - */ -/* eslint-disable no-underscore-dangle */ -workbox.precaching.precacheAndRoute(self.__precacheManifest || []); - -/** - * Register a navigation route. - * https://developers.google.com/web/tools/workbox/modules/workbox-routing#how_to_register_a_navigation_route - */ -workbox.routing.registerNavigationRoute('/index.html'); - -/** - * Use runtime cache: - * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.routing#.registerRoute - * - * Workbox provides all common caching strategies including CacheFirst, NetworkFirst etc. - * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.strategies - */ - -/** - * Handle API requests - */ -workbox.routing.registerRoute(/\/api\//, workbox.strategies.networkFirst()); - -/** - * Handle third party requests - */ -workbox.routing.registerRoute( - /^https:\/\/gw.alipayobjects.com\//, - workbox.strategies.networkFirst() -); -workbox.routing.registerRoute( - /^https:\/\/cdnjs.cloudflare.com\//, - workbox.strategies.networkFirst() -); -workbox.routing.registerRoute(/\/color.less/, workbox.strategies.networkFirst()); - -/** - * Response to client after skipping waiting with MessageChannel - */ -addEventListener('message', event => { - const replyPort = event.ports[0]; - const message = event.data; - if (replyPort && message && message.type === 'skip-waiting') { - event.waitUntil( - self.skipWaiting().then( - () => replyPort.postMessage({ error: null }), - error => replyPort.postMessage({ error }) - ) - ); - } -}); diff --git a/src/services/api.tsx b/src/services/api.tsx deleted file mode 100644 index 42d6432..0000000 --- a/src/services/api.tsx +++ /dev/null @@ -1,7 +0,0 @@ -// @ts-ignore -import request from '@/utils/request'; -import { stringify } from 'qs'; - -export async function query(params) { - return request(`/api/chapter?${stringify(params)}`); -} diff --git a/src/services/h5.tsx b/src/services/h5.tsx deleted file mode 100644 index 8bfb8ff..0000000 --- a/src/services/h5.tsx +++ /dev/null @@ -1,25 +0,0 @@ -// @ts-ignore -import request from '@/utils/request'; -import { stringify } from 'qs'; - -export async function queryChapter(params) { - return request(`/api/chapter?${stringify(params)}`); -} - -export async function queryQuestions(params) { - return request(`/api/questions?${stringify(params)}`); -} - -export async function queryTestPapers() { - return request(`/api/test/paper`); -} - -export async function saveTestResult(params) { - return request('/api/test/result', { - method: 'POST', - body: { - ...params, - method: 'post', - }, - }); -} diff --git a/src/theme.ts b/src/theme.ts deleted file mode 100644 index 3ea5efc..0000000 --- a/src/theme.ts +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - primaryColor: '#00263C', - brandPrimaryTap: '#1890ff', -}; diff --git a/src/typings.d.ts b/src/typings.d.ts deleted file mode 100644 index 6bf2c50..0000000 --- a/src/typings.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -declare module '*.css'; -declare module '*.less'; -declare module '*.scss'; -declare module '*.sass'; -declare module '*.svg'; -declare module '*.png'; -declare module '*.jpg'; -declare module '*.jpeg'; -declare module '*.gif'; -declare module '*.bmp'; -declare module '*.tiff'; -declare module 'rc-animate'; -declare module 'omit.js'; -declare module 'react-copy-to-clipboard'; -declare module 'postcss-px-to-viewport'; -declare module 'react-fittext'; -declare module 'parsec-ls'; -declare module 'slash2'; -declare module 'weixin-js-sdk'; -declare module 'qs'; -declare module 'nzh/cn'; -declare module '@/theme'; -declare var APP_TYPE: string; diff --git a/src/utils/Authorized.js b/src/utils/Authorized.js deleted file mode 100644 index 8c420cb..0000000 --- a/src/utils/Authorized.js +++ /dev/null @@ -1,12 +0,0 @@ -import RenderAuthorized from '@/components/Authorized'; -import { getAuthority } from './authority'; - -let Authorized = RenderAuthorized(getAuthority()); // eslint-disable-line - -// Reload the rights component -const reloadAuthorized = () => { - Authorized = RenderAuthorized(getAuthority()); -}; - -export { reloadAuthorized }; -export default Authorized; diff --git a/src/utils/authority.js b/src/utils/authority.js deleted file mode 100644 index c5fd649..0000000 --- a/src/utils/authority.js +++ /dev/null @@ -1,22 +0,0 @@ -// use localStorage to store the authority info, which might be sent from server in actual project. -export function getAuthority(str) { - // return localStorage.getItem('antd-mobile-authority') || ['admin', 'user']; - const authorityString = - typeof str === 'undefined' ? localStorage.getItem('antd-mobile-authority') : str; - // authorityString could be admin, "admin", ["admin"] - let authority; - try { - authority = JSON.parse(authorityString); - } catch (e) { - authority = authorityString; - } - if (typeof authority === 'string') { - return [authority]; - } - return authority || ['admin']; -} - -export function setAuthority(authority) { - const Authority = typeof authority === 'string' ? [authority] : authority; - return localStorage.setItem('antd-mobile-authority', JSON.stringify(Authority)); -} diff --git a/src/utils/authority.test.js b/src/utils/authority.test.js deleted file mode 100644 index 8a6cd41..0000000 --- a/src/utils/authority.test.js +++ /dev/null @@ -1,19 +0,0 @@ -import { getAuthority } from './authority'; - -describe('getAuthority should be strong', () => { - it('empty', () => { - expect(getAuthority(null)).toEqual(['admin']); // default value - }); - it('string', () => { - expect(getAuthority('admin')).toEqual(['admin']); - }); - it('array with double quotes', () => { - expect(getAuthority('"admin"')).toEqual(['admin']); - }); - it('array with single item', () => { - expect(getAuthority('["admin"]')).toEqual(['admin']); - }); - it('array with multiple items', () => { - expect(getAuthority('["admin", "guest"]')).toEqual(['admin', 'guest']); - }); -}); diff --git a/src/utils/debug.tsx b/src/utils/debug.tsx index 9078156..b930e5b 100644 --- a/src/utils/debug.tsx +++ b/src/utils/debug.tsx @@ -6,7 +6,7 @@ export default () => ImportCDNJS( '//res.wx.qq.com/mmbizwap/zh_CN/htmledition/js/vconsole/3.0.0/vconsole.min.js', 'VConsole' - ).then(VConsole => { + ).then((VConsole: new () => void) => { new VConsole(); resolve(); }); diff --git a/tsconfig.json b/tsconfig.json index 638b2a0..07f8efa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,34 +1,19 @@ { "compilerOptions": { - "outDir": "build/dist", - "module": "esnext", + "experimentalDecorators": true, "target": "esnext", - "lib": ["esnext", "dom"], + "module": "esnext", + "moduleResolution": "node", + "importHelpers": true, + "jsx": "react", + "esModuleInterop": true, "sourceMap": true, "baseUrl": ".", - "jsx": "react", - "allowSyntheticDefaultImports": true, - "moduleResolution": "node", - "forceConsistentCasingInFileNames": true, - "noImplicitReturns": true, - "suppressImplicitAnyIndexErrors": true, - "noUnusedLocals": true, - "allowJs": true, - "experimentalDecorators": true, "strict": true, "paths": { - "@/*": ["./src/*"] - } - }, - "exclude": [ - "node_modules", - "build", - "scripts", - "acceptance-tests", - "webpack", - "jest", - "src/setupTests.ts", - "tslint:latest", - "tslint-config-prettier" - ] + "@/*": ["src/*"], + "@tmp/*": ["src/pages/.umi/*"] + }, + "allowSyntheticDefaultImports": true + } } diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 125e217..0000000 --- a/tslint.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": ["tslint:latest", "tslint-react", "tslint-config-prettier"], - "rules": { - "no-var-requires": false, - "no-submodule-imports": false, - "object-literal-sort-keys": false, - "jsx-no-lambda": false, - "no-implicit-dependencies": false, - "no-console": false - } -} diff --git a/typings.d.ts b/typings.d.ts new file mode 100644 index 0000000..e0be95c --- /dev/null +++ b/typings.d.ts @@ -0,0 +1,10 @@ +declare module '*.css'; +declare module '*.less'; +declare module '*.scss'; +declare module '*.sass'; +declare module '*.svg'; +declare module '*.png'; +declare module '*.jpg'; +declare module '*.jpeg'; +declare module '*.gif'; +declare module 'parsec-ls';