├── .editorconfig ├── .env ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .umirc.js ├── README.md ├── favicon.ico ├── mock ├── .gitkeep ├── demo.js └── test.js ├── package.json ├── src ├── app.js ├── assets │ ├── css │ │ └── common │ │ │ ├── displaFlex.less │ │ │ └── index.less │ ├── images │ │ ├── home │ │ │ ├── Github@2x.png │ │ │ ├── android@2x.png │ │ │ ├── bg@2x-1.png │ │ │ ├── dlbg.png │ │ │ ├── ep.png │ │ │ ├── ios@2x.png │ │ │ ├── logo.png │ │ │ ├── logo@2x.png │ │ │ ├── qr.png │ │ │ ├── search@2x.png │ │ │ ├── wb-icon@2x.png │ │ │ └── wx-icon@2x.png │ │ └── login │ │ │ ├── bgimg.png │ │ │ ├── github-icon.png │ │ │ ├── github-icon@2x.png │ │ │ ├── loginbg.png │ │ │ ├── logo.jpg │ │ │ ├── logo.png │ │ │ ├── logo@2x.png │ │ │ ├── 微信-icon.png │ │ │ ├── 微信-icon@2x.png │ │ │ ├── 微博-icon.png │ │ │ ├── 微博-icon@2x.png │ │ │ ├── 闭眼-icon.png │ │ │ └── 闭眼-icon@2x.png │ ├── svg │ │ └── logo@2x.svg │ └── yay.jpg ├── component │ ├── LinkAuth.tsx │ ├── common │ │ ├── BasicFooter │ │ │ ├── index.less │ │ │ └── index.tsx │ │ └── BasicHeader │ │ │ ├── index.less │ │ │ ├── index.tsx │ │ │ └── nav.tsx │ ├── home │ │ ├── Banner │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── Download │ │ │ ├── index.less │ │ │ └── index.tsx │ │ ├── ExcellentProject │ │ │ ├── index.less │ │ │ └── index.tsx │ │ └── HomeTitle │ │ │ ├── index.less │ │ │ └── index.tsx │ └── user │ │ ├── Button.jsx │ │ ├── Input.jsx │ │ ├── Sign │ │ ├── index.less │ │ └── index.tsx │ │ └── style.less ├── global.less ├── index.d.ts ├── layouts │ ├── BasicLayout │ │ ├── index.less │ │ └── index.tsx │ ├── DisplayLayout │ │ └── index.tsx │ ├── GlobalLayout │ │ └── index.tsx │ ├── LoginLayout │ │ ├── index.tsx │ │ └── style.less │ ├── index.tsx │ └── typing.d.ts ├── models │ ├── .gitkeep │ └── globalModel.tsx ├── pages │ ├── 404.tsx │ ├── coderiver │ │ └── index.tsx │ ├── display │ │ ├── index.tsx │ │ ├── models │ │ │ └── displayModel.tsx │ │ └── service │ │ │ └── displayService.tsx │ ├── document.ejs │ ├── exception │ │ ├── 403.tsx │ │ ├── 404.tsx │ │ └── 500.tsx │ ├── index.tsx │ ├── less.css │ ├── test │ │ ├── Button.tsx │ │ ├── Computed.tsx │ │ ├── Menu.tsx │ │ └── Toggleable.tsx │ └── user │ │ ├── login │ │ └── index.tsx │ │ ├── register │ │ ├── form.tsx │ │ └── index.tsx │ │ └── style.less ├── type │ ├── common.d.ts │ └── model.d.ts └── utils │ ├── axios.tsx │ ├── nprogress │ ├── nprogress.css │ └── nprogress.js │ └── utils.js ├── test └── index.test.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | #指定覆盖默认配置的配置文件 2 | UMI_ENV=prod umi build 3 | 4 | #指定端口号 5 | PORT=8008 umi dev 6 | 7 | HOST=0.0.0.0 8 | 9 | #默认自动打开浏览器,值为none不打开 在umi dev生效 10 | $ BROWSER=none umi dev 11 | 12 | # 分析build构成 默认关闭 端口默认为8888 13 | $ ANALYZE=1 umi build 14 | $ ANALYZE_PORT=8888 15 | 16 | #默认引入polyfill 值为none不引入 2.2.0+版本支持 当前版本不支持 17 | $ BABEL_POLYFILL=none umi build 18 | 19 | #默认压缩css和js 值为none时不压缩 20 | COMPRESS=none umi build 21 | #默认压缩CSS 有时css压缩会出问题 可选择性只压缩JS 22 | CSS_COMPRESS=none umi build 23 | 24 | #默认清屏值为none不清 25 | CLEAR_CONSOLE=none 26 | 27 | #默认开启 值为none禁用 值为reload时 文件有变化刷新 28 | HMR=reload 29 | 30 | #默认不解析 31 | $ BABELRC 32 | 33 | #默认开启babel cache 值为none禁用 34 | BABEL_CACHE=none umi dev 35 | 36 | #默认开启mock 值为none禁用 37 | $ MOCK=none umi dev 38 | 39 | #默认打包html文件 值为none不打包 40 | $ HTML=none umi build 41 | 42 | #默认不开启TS检查,值为1 启用 43 | $ FORK_TS_CHECKER=1 umi dev 44 | 45 | $ WATCH_FILES 46 | $ RM_TMPDIR 47 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* eslint quotes: false*/ 2 | module.exports = { 3 | extends: ['eslint-config-alloy/typescript-react', 'eslint-config-umi'], 4 | settings: { 5 | //用于支持webpack定义的别名 (需要安装 eslint-plugin-import 和 eslint-import-resolver-webpack 插件) 6 | 'import/resolver': 'webpack', 7 | react: { 8 | createClass: 'createReactClass', // Regex for Component Factory to use, 9 | // default to "createReactClass" 10 | pragma: 'React', // Pragma to use, default to "React" 11 | version: 'detect', // React version. "detect" automatically picks the version you have installed. 12 | // You can also use `16.0`, `16.3`, etc, if you want to override the detected value. 13 | flowVersion: '0.53', // Flow version 14 | }, 15 | }, 16 | env: { 17 | browser: true, 18 | node: false, 19 | es6: true, 20 | mocha: false, 21 | commonjs: false, 22 | amd: false, 23 | }, 24 | plugins: [ 25 | 'typescript', 26 | 'react', // 插件地址 https://github.com/yannickcr/eslint-plugin-react 27 | 'import', // 插件地址 https://github.com/benmosher/eslint-plugin-import 28 | ], 29 | parserOptions: { 30 | // 基于 eslint@2.x 31 | sourceType: 'module', 32 | ecmaVersion: 6, 33 | ecmaFeatures: { 34 | jsx: true, // 迁移说明: http://eslint.org/docs/user-guide/migrating-to-2.0.0 35 | }, 36 | }, 37 | 38 | globals: { 39 | __webpack_public_path__: true, 40 | process: true, 41 | __dirname: true, 42 | CFG: true, // VM配置全局变量 43 | _: true, // lodash 全局变量 44 | React: true, 45 | ReactDom: true, 46 | KISSY: false, 47 | TB: false, 48 | JSTracker: false, 49 | JSTracker2: false, 50 | $: false, // Kimi 全局变量 51 | goldlog: true, // 黄金令箭 52 | WindVane: false, // 手淘环境 53 | require: true, // 手淘环境 54 | }, 55 | parser: 'typescript-eslint-parser', 56 | rules: { 57 | // ES6 规则 58 | // http://gitlab.alibaba-inc.com/specs/style-guide/issues/50#96 59 | 'no-redeclare': 0, 60 | 'prefer-const': 0, 61 | 'no-const-assign': 2, 62 | 'no-undefined': 0, 63 | 'no-class-assign': 2, 64 | 'no-param-reassign': 0, 65 | 'no-dupe-class-members': 2, 66 | 'rest-spread-spacing': 2, 67 | 'no-duplicate-imports': 2, 68 | 'no-useless-rename': 2, 69 | 'arrow-spacing': 2, 70 | 'no-useless-computed-key': 2, 71 | 'template-curly-spacing': 2, 72 | 'object-curly-spacing': 0, 73 | 'generator-star-spacing': [1, { before: false, after: true }], 74 | 'yield-star-spacing': [1, { before: false, after: true }], 75 | /** 76 | * 最佳实践 77 | */ 78 | strict: [0, 'global'], 79 | 'global-strict': [0, 'always'], // deprecated rule, 忽略,采用上面规则限制 80 | 'no-extra-strict': 0, 81 | 'no-shadow': 1, // 局部变量和外层变量重名 82 | 83 | // 使用该项配置会导致esLint挂掉? babel-eslint升级之8.0.0版本 84 | // "no-unused-vars": "error", 85 | 'no-unused-vars': [ 86 | 0, // 局部变量未使用 87 | { 88 | vars: 'all', 89 | args: 'after-used', 90 | }, 91 | ], 92 | 93 | 'no-undef': 0, // 未定义的变量 94 | 'no-dupe-keys': 2, // 在创建对象字面量时不允许键重复 {a:1,a:1} 95 | 'no-dupe-args': 2, // 函数参数不能重复 96 | 'no-unused-expressions': 0, // 未使用的表达式 97 | 'no-use-before-define': 0, // 允许定义前使用 98 | yoda: 0, 99 | eqeqeq: 0, 100 | 'no-new': 0, // 允许 new 创建的对象没有被引用 101 | 'consistent-return': 0, // 允许没有 return 102 | 'dot-notation': [ 103 | 2, 104 | { 105 | // 操作对象属性时,优先使用 . 操作 106 | allowKeywords: true, 107 | }, 108 | ], 109 | 'no-extend-native': 2, // 禁止通过 prototype 给原生对象增加额外方法。 110 | 'no-native-reassign': 2, // 阻止复写内置类型 111 | 'no-return-assign': 2, // 是否允许 return 返回表达式 112 | 'no-return-await': 0, // 是否允许 await 返回表达式 113 | 'no-constant-condition': [ 114 | 2, 115 | { 116 | checkLoops: false, 117 | }, 118 | ], // 提示拒绝使用已经明确意义的判断条件 if (true) 119 | 'max-len': [ 120 | 1, 121 | 200, 122 | 2, 123 | { 124 | ignoreComments: true, 125 | ignoreUrls: true, 126 | }, 127 | ], 128 | 129 | 'no-caller': 2, 130 | 'no-loop-func': 1, 131 | 132 | // nodejs 环境规则 133 | //"no-console": "warn", // 代码禁止出现 console 134 | 'no-catch-shadow': 2, // try catch 捕获的变量名禁止重名定义 135 | 'no-new-require': 0, // require 前面是否能添加 new 136 | 'no-mixed-requires': [0, false], // 是否合并 var requires 137 | 'no-path-concat': 0, // 是否可以自行拼接 path 还是必须要引用 path 模块 138 | 'handle-callback-err': 0, // 代码里面是否有处理 err 的逻辑? 139 | 140 | /** 141 | * 代码风格 142 | */ 143 | 'no-empty': 0, // 允许空 block 语句 144 | indent: [ 145 | 2, 146 | 2, 147 | { 148 | // 缩进 149 | SwitchCase: 1, 150 | }, 151 | ], 152 | camelcase: [ 153 | 1, 154 | { 155 | // 驼峰,同时检查属性名 156 | properties: 'always', 157 | }, 158 | ], 159 | quotes: [2, 'single', 'avoid-escape'], // 引号,强制使用单引号 160 | 'brace-style': [ 161 | 2, 162 | '1tbs', 163 | { 164 | allowSingleLine: false, 165 | }, 166 | ], 167 | 'comma-spacing': [ 168 | 2, 169 | { 170 | // 逗号空格 171 | before: false, 172 | after: true, 173 | }, 174 | ], 175 | 'comma-style': [2, 'last'], // 逗号风格 176 | 'eol-last': 0, // 最后留一行空行 177 | 'func-names': 0, // 是否所有函数必须命名 178 | 'new-cap': [ 179 | 1, 180 | { 181 | // 类名首字母大写 182 | newIsCap: true, 183 | }, 184 | ], 185 | 'key-spacing': [ 186 | 2, 187 | { 188 | // object 的 key value :的前后空格 189 | beforeColon: false, 190 | afterColon: true, 191 | }, 192 | ], 193 | 'no-multi-spaces': 2, // 表达式中是否允许多个空格 194 | 'no-multiple-empty-lines': 0, // 是否允许多行空格 195 | 'no-nested-ternary': 0, // 是否禁止三目运算 196 | 'no-new-object': 2, // 禁止 new Object() 197 | 'no-spaced-func': 2, // 函数与括号的空格 198 | 'no-trailing-spaces': 0, // 是否允许末尾有空格 199 | 'no-extra-parens': [1, 'functions'], // "no-wrap-func": 1, 禁止额外的括号 允许括号内是方法 200 | 'no-underscore-dangle': 0, // 允许任意使用下划线 201 | 'one-var': [1, 'consecutive'], // 定义变量一行一个 202 | 'padded-blocks': [0, 'never'], // 块代码上下不能留空行 203 | semi: 0, // 校验分号 204 | 'semi-spacing': 2, // 分号后面留空 205 | 'keyword-spacing': 2, // 关键词后面加空格 206 | 'space-before-blocks': 2, // 块级代码加空格 207 | 'space-infix-ops': 0, // 操作符之间的空格 208 | 'spaced-comment': [ 209 | 1, 210 | 'always', 211 | { 212 | line: { 213 | markers: ['/'], 214 | exceptions: ['-', '+'], 215 | }, 216 | block: { 217 | markers: ['!'], 218 | exceptions: ['*'], 219 | balanced: true, 220 | }, 221 | }, 222 | ], // 注释斜线后面是否需要空格 223 | 224 | /** 225 | * ts 规范 226 | */ 227 | 228 | // 'typescript/no-constant-condition': 2, 229 | 'typescript/quotemark': [true, 'single', 'avoid-escape', 'jsx-double'], 230 | 'typescript/no-console': 0, 231 | 'typescript/ordered-imports': 0, 232 | 'typescript/no-namespace': 0, 233 | 'typescript/object-literal-sort-keys': 0, 234 | 'typescript/arrow-parens': 0, 235 | 'typescript/no-empty': 0, 236 | 'typescript/no-var-requires': 0, 237 | 'typescript/array-type': 0, 238 | // 'typescript/member-ordering': [true,{ 239 | // "order":[ 240 | // "private-static-field", 241 | // "protected-static-field", 242 | // "public-static-field", 243 | // "private-instence-field", 244 | // "protected-instence-field", 245 | // "public-instence-field", 246 | // "private-constructor", 247 | // "protected-constructor", 248 | // "public-constructor", 249 | // "private-static-method", 250 | // "protected-static-method", 251 | // "public-static-method", 252 | // "private-instence-method", 253 | // "protected-instence-method", 254 | // "public-instence-method" 255 | // ] 256 | // }], 257 | 'typescript/object-literal-key-quotes': [true, 'as-needed'], 258 | 'typescript/no-trailing-whitespace': [false, 'ignore-comments'], 259 | 'typescript/class-name-casing': 2, 260 | 261 | /** 262 | * React JSX 规范 263 | */ 264 | 'react/display-name': 0, // 是否显示 Component 名称 265 | 'react/jsx-boolean-value': [0, 'always'], // 传递布尔值时是否明确支持 266 | 'jsx-quotes': [2, 'prefer-double'], // jsx 属性值用双引号 267 | 'react/jsx-no-undef': 2, // 判断 jsx 是否已经定义 268 | 'react/jsx-sort-props': 0, // 是否排序 props 269 | 'react/jsx-sort-prop-types': 0, // 是否排序 prop types 270 | 'react/jsx-uses-react': 2, // 组件中中是否用了 react 271 | 'react/jsx-uses-vars': 2, // 定义了 jsx component 没有使用 272 | 'react/jsx-pascal-case': 1, // 使用jsx作为组件扩展名,采用pascal命名法 引用名采用驼峰命名 273 | 'react/jsx-closing-bracket-location': 1, // 组件prop的的对齐风格 274 | 'react/no-did-mount-set-state': 0, // 不要在 componentDidMount 里面设置 state 275 | 'react/no-did-update-set-state': 0, // 同上 276 | 'react/no-multi-comp': 0, // 一个文件里面禁止声明多个 component 277 | 'react/no-unknown-property': 2, // 检查 class、for 属性是否转义 278 | 'react/prop-types': 0, // 不强制设置 proptypes 279 | 'react/react-in-jsx-scope': 1, // 查看 jsx 是否引入 react 280 | 'react/self-closing-comp': 2, // 检查是否有没有 children 的非子闭合标签 281 | 'react/jsx-wrap-multilines': 1, // 不强制 return 的时候,结构的格式 282 | 'react/prefer-es6-class': 1, // 使用组件类继承React.Component 283 | 'react/sort-comp': [ 284 | 0, 285 | { 286 | // 不强制 createClass 属性的排序 287 | order: [ 288 | 'lifecycle', 289 | '/^on.+$/', 290 | '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/', 291 | 'everything-else', 292 | '/^render.+$/', 293 | 'render', 294 | ], 295 | }, 296 | ], 297 | 'react/jsx-indent-props': 0, 298 | 299 | 'no-var': 0, 300 | }, 301 | }; 302 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /npm-debug.log* 6 | /yarn-error.log 7 | yarn.lock 8 | /package-lock.json 9 | 10 | # production 11 | /dist 12 | 13 | # misc 14 | .DS_Store 15 | 16 | # umi 17 | .umi 18 | .umi-production 19 | 20 | # ide 21 | .idea 22 | 23 | .eslintrc.1.js 24 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.md 2 | **/*.svg 3 | **/*.ejs 4 | **/*.html 5 | package.json 6 | .umi 7 | .umi-production 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "printWidth": 100, 5 | "overrides": [ 6 | { 7 | "files": ".prettierrc", 8 | "options": { "parser": "json" } 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.umirc.js: -------------------------------------------------------------------------------- 1 | // ref: https://umijs.org/config/ 2 | 3 | import path from 'path'; 4 | 5 | export default { 6 | plugins: [ 7 | // ref: https://umijs.org/plugin/umi-plugin-react.html 8 | [ 9 | 'umi-plugin-react', 10 | { 11 | antd: true, 12 | dva: true, 13 | dynamicImport: true, 14 | title: 'umi-ts', 15 | dll: true, 16 | routes: { 17 | exclude: [/models/, /service/], 18 | }, 19 | // hardSource: true, 20 | }, 21 | ], 22 | ], 23 | publicPath: '/code-river-pc/', 24 | history: 'hash', 25 | cssLoaderOptions: {}, 26 | alias: { 27 | component: path.resolve(__dirname, './src/component'), 28 | assets: path.resolve(__dirname, './src/assets'), 29 | }, 30 | chainWebpack(config, { webpack }) { 31 | // config.plugin('analyzer').use( 32 | // new BundleAnalyzerPlugin({ 33 | // // 可以是`server`,`static`或`disabled`。 34 | // // 在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。 35 | // // 在“静态”模式下,会生成带有报告的单个HTML文件。 36 | // // 在`disabled`模式下,你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。 37 | // analyzerMode: 'static', 38 | // // 将在“服务器”模式下使用的主机启动HTTP服务器。 39 | // analyzerHost: 'localhost', 40 | // // 将在“服务器”模式下使用的端口启动HTTP服务器。 41 | // analyzerPort: 9999, 42 | // // 路径捆绑,将在`static`模式下生成的报告文件。 43 | // // 相对于捆绑输出目录。 44 | // reportFilename: 'report.html', 45 | // // 模块大小默认显示在报告中。 46 | // // 应该是`stat`,`parsed`或者`gzip`中的一个。 47 | // // 有关更多信息,请参见“定义”一节。 48 | // defaultSizes: 'parsed', 49 | // // 在默认浏览器中自动打开报告 50 | // openAnalyzer: false, 51 | // // 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成 52 | // generateStatsFile: false, 53 | // // 如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。 54 | // // 相对于捆绑输出目录。 55 | // statsFilename: 'stats.json', 56 | // // stats.toJson()方法的选项。 57 | // // 例如,您可以使用`source:false`选项排除统计文件中模块的来源。 58 | // // 在这里查看更多选项:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21 59 | // statsOptions: null, 60 | // logLevel: 'info', // 日志级别。可以是'信息','警告','错误'或'沉默'。 61 | // }) 62 | // ); 63 | config.resolve.alias.set('src', path.resolve(__dirname, './src')); 64 | config.resolve.alias.set('component', path.resolve(__dirname, './src/component')); 65 | config.resolve.alias.set('assets', path.resolve(__dirname, './src/assets')); 66 | // config.module 67 | // .rule('save') 68 | // .test(/\.less$/) 69 | // .use('less') 70 | // .loader('typings-for-css-modules-loader') 71 | // .options({ 72 | // modules: true, 73 | // namedExport: true, 74 | // localIdentName: '[local]_[hash:base64:6]', 75 | // minimize: true, 76 | // }); 77 | }, 78 | }; 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CodeRiver 2 | 3 | CodeRiver PC 4 | 5 | 6 | ## Git Flow 7 | 8 | 1. 开发者(A,B,C)都会再当前项目的组中,会有当前项目的权限 9 | 2. 开发者统一在 `dev` 分支进行开发,日常提交至Dev 10 | 3. 当某一个模块完成是,`merge` 至 `master`. 11 | 12 | ## Commit Message(尽量使用英文) 13 | 14 | - feat:新功能(feature) 15 | - fix:修补bug 16 | - docs:文档(documentation) 17 | - style: 格式(不影响代码运行的变动) 18 | - refactor:重构(即不是新增功能,也不是修改bug的代码变动) 19 | - test:增加测试 20 | - chore:构建过程或辅助工具的变动 21 | 22 | `Example` 23 | 24 | > feat : update module-login ui 25 | 26 | > docs : add gitflow && commit message style 27 | 28 | > fix : can't login success (module-login) 29 | 30 | 31 | ## 当前Task 32 | 33 | 1. 所有开发者统一完成登录模块(样式,交互,校验逻辑) 34 | 2. 开发周期(`1week`) 35 | 3. 一周后,大家在Github的项目中进行review(组件拆分思想,目录组织方式,命名规范) 36 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/favicon.ico -------------------------------------------------------------------------------- /mock/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/mock/.gitkeep -------------------------------------------------------------------------------- /mock/demo.js: -------------------------------------------------------------------------------- 1 | import mockjs from 'mockjs'; 2 | 3 | // import { formatRes } from '../src/utils/utils'; 4 | 5 | const formatRes = (data, code = '0000') => { 6 | return { 7 | data, 8 | code, 9 | message: code === '0000' ? '请求成功' : '请求失败', 10 | }; 11 | }; 12 | 13 | export default { 14 | 'GET /api/v1/test': (req, res) => { 15 | // res.setHeader('Access-Control-Allow-Origin', '*'); 16 | // res.setHeader('Content-Type', 'application/json'); 17 | const data = mockjs.mock({ 18 | 'list|100': [ 19 | { 20 | name: '@city', 21 | 'value|1-100': 50, 22 | 'type|0-2': 1, 23 | }, 24 | ], 25 | }); 26 | setTimeout(() => { 27 | res.send(formatRes(data)); 28 | }, 2000); 29 | }, 30 | // 'GET /api/v1/test': { 31 | // a: 123, 32 | // }, 33 | }; 34 | -------------------------------------------------------------------------------- /mock/test.js: -------------------------------------------------------------------------------- 1 | import mockjs from 'mockjs'; 2 | 3 | // import { formatRes } from '../src/utils/utils'; 4 | 5 | const formatRes = (data, code = '0000') => { 6 | return { 7 | data, 8 | code, 9 | message: code === '0000' ? '请求成功' : '请求失败', 10 | }; 11 | }; 12 | 13 | export default { 14 | 'GET /api/v1/test': (req, res) => { 15 | // res.setHeader('Access-Control-Allow-Origin', '*'); 16 | // res.setHeader('Content-Type', 'application/json'); 17 | const data = mockjs.mock({ 18 | 'list|100': [ 19 | { 20 | name: '@city', 21 | 'value|1-100': 50, 22 | 'type|0-2': 1, 23 | }, 24 | ], 25 | }); 26 | setTimeout(() => { 27 | res.send(formatRes(data)); 28 | }, 2000); 29 | }, 30 | // 'GET /api/v1/test': { 31 | // a: 123, 32 | // }, 33 | }; 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "umi dev", 5 | "build": "umi build", 6 | "test": "umi test", 7 | "lint": "eslint --ext .js .tsx src mock tests" 8 | }, 9 | "devDependencies": { 10 | "babel-eslint": "^7.2.3", 11 | "eslint": "^4.19.1", 12 | "eslint-config-umi": "^0.1.5", 13 | "eslint-plugin-flowtype": "^2.50.0", 14 | "eslint-plugin-import": "^2.14.0", 15 | "eslint-plugin-jsx-a11y": "^5.1.1", 16 | "eslint-plugin-react": "^7.11.1", 17 | "husky": "^0.14.3", 18 | "lint-staged": "^7.2.2", 19 | "umi": "^2.1.6", 20 | "umi-plugin-react": "^1.1.1" 21 | }, 22 | "lint-staged": { 23 | "*.{js,jsx,ts,tsx}": [ 24 | "eslint --fix", 25 | "git add" 26 | ] 27 | }, 28 | "engines": { 29 | "node": ">=8.0.0" 30 | }, 31 | "dependencies": { 32 | "@material-ui/core": "^3.9.0", 33 | "@material-ui/icons": "^3.0.1", 34 | "@material-ui/styles": "^3.0.0-alpha.8", 35 | "axios": "^0.18.0", 36 | "dva-core": "1.1.0", 37 | "eslint-config-alloy": "^1.4.2", 38 | "eslint-plugin-typescript": "^0.14.0", 39 | "jss": "10.0.0-alpha.3", 40 | "mockjs": "^1.0.1-beta3", 41 | "nprogress": "^0.2.0", 42 | "react": "16.7.0-alpha.2", 43 | "react-dom": "16.7.0-alpha.2", 44 | "react-router": "4.4.0-beta.1", 45 | "redbox-react": "1.x", 46 | "redux": "3.x", 47 | "typescript": "*", 48 | "typescript-eslint-parser": "^21.0.1", 49 | "webpack-bundle-analyzer": "^3.0.3" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | export const dva = { 4 | config: { 5 | onError(err) { 6 | err.preventDefault(); 7 | console.error(err.message); 8 | }, 9 | }, 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /src/assets/css/common/displaFlex.less: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | .displayFlex{ 4 | display: flex; 5 | display:-webkit-box; 6 | display: -moz-box; 7 | display: -ms-flexbox; 8 | display: -webkit-flex; 9 | } 10 | 11 | .flex-direction-row{ 12 | -webkit-box-orient:horizontal; 13 | -webkit-box-direction:normal; 14 | -moz-box-orient:horizontal; 15 | -moz-box-direction:normal; 16 | flex-direction:row; 17 | -webkit-flex-direction:row; 18 | } 19 | .flex-direction-column{ 20 | -webkit-box-orient:vertical; 21 | -webkit-box-direction:normal; 22 | -moz-box-orient:vertical; 23 | -moz-box-direction:normal; 24 | flex-direction:column; 25 | -webkit-flex-direction:column; 26 | } 27 | .flex-justify-content{ 28 | -webkit-justify-content:center; 29 | justify-content:center; 30 | -moz-box-pack:center; 31 | -webkit-box-pack:center; 32 | box-pack:center; 33 | } 34 | .flex-justify-right{ 35 | -webkit-justify-content: flex-end; 36 | justify-content:flex-end; 37 | -moz-box-pack:end; 38 | -webkit-box-pack:end; 39 | box-pack:end; 40 | } 41 | .flex-justify-between{ 42 | -webkit-justify-content: space-between; 43 | justify-content:space-between; 44 | -moz-box-pack:justify; 45 | -webkit-box-pack:justify; 46 | box-pack:space-between; 47 | } 48 | .flex-align-items { 49 | align-items: center; 50 | -webkit-align-items:center; 51 | box-align:center; 52 | -moz-box-align:center; 53 | -webkit-box-align:center; 54 | 55 | } 56 | .flex-align-end { 57 | align-items: end; 58 | -webkit-align-items: flex-end; 59 | -moz-box-align:end; 60 | -webkit-box-align:end; 61 | 62 | } 63 | .flex-wrap{ 64 | -webkit-flex-wrap:wrap; 65 | -webkit-box-lines:multiple; 66 | -moz-flex-wrap:wrap; 67 | flex-wrap:wrap; 68 | } 69 | .flex-1{ 70 | -moz-box-flex: 1.0; /*Firefox*/ 71 | -webkit-box-flex: 1.0; /*Safari,Opera,Chrome*/ 72 | box-flex: 1.0; 73 | flex:1; 74 | } 75 | .flex-justify-align{ 76 | display: flex; 77 | display:-webkit-box; 78 | display: -moz-box; 79 | display: -ms-flexbox; 80 | display: -webkit-flex; 81 | -webkit-justify-content:center; 82 | justify-content:center; 83 | -moz-box-pack:center; 84 | -webkit-box-pack:center; 85 | box-pack:center; 86 | align-items:center; 87 | -webkit-align-items:center; 88 | box-align:center; 89 | -moz-box-align:center; 90 | -webkit-box-align:center; 91 | } 92 | .justify-align{ 93 | -webkit-justify-content:center; 94 | justify-content:center; 95 | -moz-box-pack:center; 96 | -webkit-box-pack:center; 97 | box-pack:center; 98 | align-items:center; 99 | -webkit-align-items:center; 100 | box-align:center; 101 | -moz-box-align:center; 102 | -webkit-box-align:center; 103 | } 104 | .flex-justify{ 105 | display: flex; 106 | display:-webkit-box; 107 | display: -moz-box; 108 | display: -ms-flexbox; 109 | display: -webkit-flex; 110 | -webkit-justify-content:center; 111 | justify-content:center; 112 | -moz-box-pack:center; 113 | -webkit-box-pack:center; 114 | box-pack:center; 115 | } 116 | .border_bottom (@color){ 117 | &:before { 118 | position: absolute; 119 | bottom: 0; 120 | left: 0; 121 | content: ''; 122 | width: 100%; 123 | height: 1px; 124 | border-bottom: 1px solid @color; 125 | -webkit-transform: scaleY(0.5); 126 | transform: scaleY(0.5); 127 | } 128 | } 129 | .border_top (@color){ 130 | &:before { 131 | position: absolute; 132 | top: -1px; 133 | left: 0; 134 | content: ''; 135 | width: 100%; 136 | height: 1px; 137 | border-top: 1px solid @color; 138 | -webkit-transform: scaleY(0.5); 139 | transform: scaleY(0.5); 140 | } 141 | } 142 | .border_right(@color){ 143 | &:before { 144 | position: absolute; 145 | top: 0; 146 | right: -1px; 147 | left: 0; 148 | content: ''; 149 | height: 100%; 150 | width: 1px; 151 | border-right: 1px solid @color; 152 | -webkit-transform: scaleX(0.5); 153 | transform: scaleX(0.5); 154 | } 155 | } 156 | .border_left(@color){ 157 | &:before { 158 | position: absolute; 159 | top: 0; 160 | left: -1px; 161 | right: 0; 162 | content: ''; 163 | height: 100%; 164 | width: 1px; 165 | border-lef: 1px solid @color; 166 | -webkit-transform: scaleY(0.5); 167 | transform: scaleY(0.5); 168 | } 169 | } 170 | .duohang(@number) { 171 | display: -webkit-box; 172 | -webkit-box-orient: vertical; 173 | -webkit-line-clamp: @number; 174 | overflow: hidden; 175 | } 176 | //单行 177 | .danhang { 178 | overflow:hidden; 179 | text-overflow:ellipsis; 180 | white-space:nowrap 181 | } 182 | .textareaPLaceholder(@color){ 183 | 184 | textarea::-webkit-input-placeholder { /* WebKit, Blink, Edge */ 185 | color:@color; 186 | } 187 | textarea:-moz-placeholder { /* Mozilla Firefox 4 to 18 */ 188 | color:@color; 189 | } 190 | textarea::-moz-placeholder { /* Mozilla Firefox 19+ */ 191 | color:@color; 192 | } 193 | textarea:-ms-input-placeholder { /* Internet Explorer 10-11 */ 194 | color:@color; 195 | } 196 | 197 | } 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /src/assets/css/common/index.less: -------------------------------------------------------------------------------- 1 | @header-nav-color: #40aea8; 2 | @footer-border-color: #40aea8; 3 | @theme-color: #40aea8; 4 | @primary-color: #0194a3; 5 | 6 | p { 7 | margin: 0; 8 | line-height: 1; 9 | } 10 | -------------------------------------------------------------------------------- /src/assets/images/home/Github@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/Github@2x.png -------------------------------------------------------------------------------- /src/assets/images/home/android@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/android@2x.png -------------------------------------------------------------------------------- /src/assets/images/home/bg@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/bg@2x-1.png -------------------------------------------------------------------------------- /src/assets/images/home/dlbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/dlbg.png -------------------------------------------------------------------------------- /src/assets/images/home/ep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/ep.png -------------------------------------------------------------------------------- /src/assets/images/home/ios@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/ios@2x.png -------------------------------------------------------------------------------- /src/assets/images/home/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/logo.png -------------------------------------------------------------------------------- /src/assets/images/home/logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/logo@2x.png -------------------------------------------------------------------------------- /src/assets/images/home/qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/qr.png -------------------------------------------------------------------------------- /src/assets/images/home/search@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/search@2x.png -------------------------------------------------------------------------------- /src/assets/images/home/wb-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/wb-icon@2x.png -------------------------------------------------------------------------------- /src/assets/images/home/wx-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/home/wx-icon@2x.png -------------------------------------------------------------------------------- /src/assets/images/login/bgimg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/bgimg.png -------------------------------------------------------------------------------- /src/assets/images/login/github-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/github-icon.png -------------------------------------------------------------------------------- /src/assets/images/login/github-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/github-icon@2x.png -------------------------------------------------------------------------------- /src/assets/images/login/loginbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/loginbg.png -------------------------------------------------------------------------------- /src/assets/images/login/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/logo.jpg -------------------------------------------------------------------------------- /src/assets/images/login/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/logo.png -------------------------------------------------------------------------------- /src/assets/images/login/logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/logo@2x.png -------------------------------------------------------------------------------- /src/assets/images/login/微信-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/微信-icon.png -------------------------------------------------------------------------------- /src/assets/images/login/微信-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/微信-icon@2x.png -------------------------------------------------------------------------------- /src/assets/images/login/微博-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/微博-icon.png -------------------------------------------------------------------------------- /src/assets/images/login/微博-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/微博-icon@2x.png -------------------------------------------------------------------------------- /src/assets/images/login/闭眼-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/闭眼-icon.png -------------------------------------------------------------------------------- /src/assets/images/login/闭眼-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/images/login/闭眼-icon@2x.png -------------------------------------------------------------------------------- /src/assets/svg/logo@2x.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/yay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/assets/yay.jpg -------------------------------------------------------------------------------- /src/component/LinkAuth.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'umi/link'; 2 | 3 | type linkProps = { 4 | to: 5 | | string 6 | | { 7 | pathname: string; 8 | search?: string; 9 | hash?: string; 10 | state?: any; 11 | }; 12 | replace?: boolean; 13 | innerRef?: Function; 14 | title?: string; 15 | id?: string; 16 | className?: string; 17 | }; 18 | 19 | export default function LinkAuth(props: linkProps) { 20 | 21 | return ; 22 | } 23 | -------------------------------------------------------------------------------- /src/component/common/BasicFooter/index.less: -------------------------------------------------------------------------------- 1 | @import url('../../../assets/css/common/index'); 2 | 3 | .cr-footer { 4 | width: 100%; 5 | height: 390px; 6 | border-top: 4px solid @footer-border-color; 7 | background: #fff; 8 | font-family: 'Microsoft YaHei UI'; 9 | font-weight: bold; 10 | display: flex; 11 | :global { 12 | .cr-footer-left { 13 | width: 835px; 14 | padding-right: 100px; 15 | text-align: left; 16 | font-size: 18px; 17 | flex-shrink: 0; 18 | > p { 19 | margin: 0; 20 | } 21 | > p:last-child { 22 | font-size: 20px; 23 | margin-top: 20px; 24 | } 25 | .cr-footer-logo { 26 | margin-top: 60px; 27 | margin-bottom: 30px; 28 | img { 29 | width: 214px; 30 | height: 50px; 31 | } 32 | } 33 | } 34 | .cr-footer-right { 35 | text-align: left; 36 | font-weight: normal; 37 | .cr-friendly-link-title { 38 | font-size: 40px; 39 | margin-top: 60px; 40 | line-height: 50px; 41 | margin-bottom: 30px; 42 | } 43 | .cr-friendly-link { 44 | font-size: 20px; 45 | > ul { 46 | list-style: none; 47 | margin: 0; 48 | padding: 0; 49 | li { 50 | float: left; 51 | margin-right: 20px; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/component/common/BasicFooter/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import styles from './index.less'; 3 | import logo from 'assets/images/home/logo@2x.png'; 4 | import android from 'assets/images/home/android@2x.png'; 5 | import ios from 'assets/images/home/ios@2x.png'; 6 | import github from 'assets/images/home/Github@2x.png'; 7 | import wbicon from 'assets/images/home/wb-icon@2x.png'; 8 | import wxicon from 'assets/images/home/wx-icon@2x.png'; 9 | 10 | export default class BasicFooter extends Component { 11 | render() { 12 | return ( 13 | 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/component/common/BasicHeader/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../assets/css/common/index'; 2 | .header-box { 3 | position: fixed; 4 | width: 100%; 5 | top: 0; 6 | box-shadow: 0 0 16px 0 #ccc; 7 | background-color: #ffffff; 8 | z-index: 10; 9 | :global { 10 | .cr-header { 11 | width: 1220px; 12 | margin: 0 auto; 13 | display: flex; 14 | height: 80px; 15 | .cr-logo { 16 | flex-shrink: 0; 17 | 18 | img { 19 | width: 214px; 20 | height: 50px; 21 | margin: 10px 20px 20px; 22 | } 23 | } 24 | 25 | .cr-nav { 26 | flex: 1; 27 | margin-bottom: 8px; 28 | align-self: center; 29 | overflow: hidden; 30 | } 31 | 32 | .cr-user { 33 | flex-shrink: 0; 34 | font-size: 20px; 35 | line-height: 80px; 36 | 37 | > span, 38 | > i { 39 | margin: 0 15px; 40 | } 41 | 42 | > i { 43 | font-weight: bold; 44 | } 45 | } 46 | 47 | .ant-menu-item { 48 | font-size: 20px; 49 | color: #000; 50 | line-height: 68px; 51 | margin: 0 10px; 52 | border-bottom: 4px solid transparent; 53 | } 54 | 55 | .ant-menu-item-selected, 56 | .ant-menu-item:hover { 57 | border-bottom: 4px solid @header-nav-color; 58 | color: #000000; 59 | } 60 | 61 | .ant-menu-item-active .ant-menu-item-selected { 62 | border-bottom: 4px solid @header-nav-color; 63 | } 64 | 65 | .ant-menu-horizontal { 66 | border: none; 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/component/common/BasicHeader/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import styles from './index.less'; 3 | import { Menu, Icon } from 'antd'; 4 | import logo from 'assets/svg/logo@2x.svg'; 5 | import router from 'umi/router'; 6 | import Nav from './nav'; 7 | import Search from '@material-ui/icons/Search'; 8 | 9 | export default class BasicHeader extends Component { 10 | state = { 11 | current: 'home', 12 | }; 13 | 14 | handleClick = e => { 15 | console.log('click ', e); 16 | this.setState({ 17 | current: e.key, 18 | }); 19 | }; 20 | 21 | render() { 22 | const Nav = props => ( 23 | 24 | 首页 25 | 项目中心 26 | 人才广场 27 | 28 | ); 29 | return ( 30 |
31 |
32 |
33 | 34 |
35 |
36 |
39 |
40 | 41 | { 43 | router.push('/user/login'); 44 | }} 45 | > 46 | 登录 47 | 48 | { 50 | router.push('/user/register'); 51 | }} 52 | > 53 | 注册 54 | 55 |
56 |
57 |
58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/component/common/BasicHeader/nav.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { makeStyles, withStyles } from '@material-ui/styles'; 3 | import Paper from '@material-ui/core/Paper'; 4 | import Tabs from '@material-ui/core/Tabs'; 5 | import Tab from '@material-ui/core/Tab'; 6 | 7 | const useStyles = makeStyles({ 8 | root: { 9 | flexGrow: 1, 10 | }, 11 | labelFont: { 12 | fontSize: '20px !important', 13 | lineHeight: '60px !important', 14 | color: '#40aea8 !important', 15 | // borderBottom: '4px solid #40aea8 !important', 16 | }, 17 | }); 18 | 19 | const MTabs = withStyles({ 20 | indicator: { 21 | height: '4px !important', 22 | backgroundColor: '#40aea8 !important', 23 | }, 24 | })(Tabs); 25 | 26 | function Nav() { 27 | const classes = useStyles(); 28 | const [value, setValue] = React.useState(0); 29 | 30 | function handleChange(event, newValue) { 31 | setValue(newValue); 32 | } 33 | 34 | return ( 35 | 36 | 43 | 44 | 45 | 46 | 47 | 48 | ); 49 | } 50 | 51 | export default Nav; 52 | -------------------------------------------------------------------------------- /src/component/home/Banner/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../assets/css/common/index'; 2 | .home-banner { 3 | height: 560px; 4 | :global { 5 | .home-banner-box { 6 | position: relative; 7 | height: 560px; 8 | background-image: url('/src/assets/images/home/bg@2x-1.png'); 9 | .home-banner-box-img { 10 | width: 100%; 11 | height: 100%; 12 | overflow: hidden; 13 | text-align: left; 14 | p { 15 | font-size: 64px; 16 | margin: 0; 17 | line-height: 1; 18 | } 19 | p:nth-child(1) { 20 | color: #4688f1; 21 | margin-top: 100px; 22 | } 23 | p:nth-child(2) { 24 | color: #000; 25 | margin-top: 30px; 26 | } 27 | .banner-button-group { 28 | margin-top: 60px; 29 | button { 30 | width: 150px; 31 | height: 50px; 32 | background-color: transparent; 33 | font-size: 20px; 34 | &:focus { 35 | outline: none; 36 | opacity: 0.6; 37 | } 38 | } 39 | button:nth-child(1) { 40 | border: 2px solid #000000; 41 | color: #000000; 42 | } 43 | button:nth-child(2) { 44 | border: 2px solid @theme-color; 45 | color: @theme-color; 46 | margin-left: 20px; 47 | } 48 | } 49 | } 50 | } 51 | 52 | .ant-carousel .slick-dots { 53 | bottom: 30px; 54 | li { 55 | margin: 0 6px; 56 | button { 57 | width: 10px; 58 | height: 10px; 59 | border-radius: 100%; 60 | background-color: rgba(0, 0, 0, 0.2); 61 | opacity: 1; 62 | } 63 | 64 | .slick-slide { 65 | text-align: center; 66 | height: 560px; 67 | line-height: 160px; 68 | background: #364d79; 69 | overflow: hidden; 70 | h3 { 71 | color: #fff; 72 | } 73 | } 74 | &.slick-active button { 75 | background-color: rgba(70, 136, 241, 0.8); 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/component/home/Banner/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Carousel } from 'antd'; 3 | import styles from './index.less'; 4 | import bgimg from 'assets/images/home/bg@2x-1.png'; 5 | 6 | export default function Banner(props) { 7 | const onChange = (a = 0, b = 0, c = 0): void => { 8 | console.log(a, b, c); 9 | }; 10 | return ( 11 |
12 | 13 |
14 |
15 |
23 |

近23万优秀开发者

24 |

您的专属云端开发团队

25 |
26 | 27 | 28 |
29 |
30 |
31 |
32 |
33 |
34 |
42 |

近23万优秀开发者

43 |

您的专属云端开发团队

44 |
45 | 46 | 47 |
48 |
49 |
50 |
51 |
52 |
53 |
61 |

近23万优秀开发者

62 |

您的专属云端开发团队

63 |
64 | 65 | 66 |
67 |
68 |
69 |
70 |
71 |
72 |
80 |

近23万优秀开发者

81 |

您的专属云端开发团队

82 |
83 | 84 | 85 |
86 |
87 |
88 |
89 |
90 |
91 | ); 92 | } 93 | -------------------------------------------------------------------------------- /src/component/home/Download/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../assets/css/common/index'; 2 | 3 | .coderiver-download { 4 | width: 100%; 5 | text-align: left; 6 | :global { 7 | .coderiver-download-main { 8 | width: 100%; 9 | height: 520px; 10 | background-size: 150%; 11 | background-repeat: no-repeat; 12 | background-position: 46% -110px; 13 | button { 14 | position: relative; 15 | width: 300px; 16 | height: 70px; 17 | font-size: 26px; 18 | font-family: 'Microsoft YaHei UI', serif; 19 | background-color: transparent; 20 | outline: none; 21 | border: 2px solid #000; 22 | transition: all 0.5s; 23 | &:focus { 24 | opacity: 0.5; 25 | } 26 | &:nth-child(2) { 27 | margin-left: 30px; 28 | } 29 | img { 30 | position: absolute; 31 | left: 0; 32 | height: 0; 33 | top: 70px; 34 | width: 300px; 35 | transition: all 0.5s; 36 | } 37 | &:hover { 38 | img { 39 | height: 300px; 40 | } 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/component/home/Download/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import HomeTitle from '../HomeTitle'; 3 | import styles from './index.less'; 4 | import dl from 'assets/images/home/dlbg.png'; 5 | import qr from 'assets/images/home/qr.png'; 6 | import { Icon } from 'antd'; 7 | 8 | export default function CodeRiverDownload(props) { 9 | return ( 10 |
11 | 12 |
13 | 18 | 23 |
24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src/component/home/ExcellentProject/index.less: -------------------------------------------------------------------------------- 1 | @import '../../../assets/css/common/index'; 2 | .excellent-project { 3 | margin-bottom: 20px; 4 | :global { 5 | .excellent-project-main { 6 | display: grid; 7 | grid-template-rows: auto; 8 | grid-template-columns: 1fr 1fr; 9 | grid-template-areas: none; 10 | grid-auto-flow: initial; 11 | grid-auto-rows: initial; 12 | grid-auto-columns: initial; 13 | text-align: left; 14 | transition: all 0.5s; 15 | .excellent-project-main-box { 16 | padding: 30px; 17 | transition: all 0.5s; 18 | position: relative; 19 | top: 0; 20 | left: 0; 21 | .img { 22 | width: 550px; 23 | height: 368px; 24 | overflow: hidden; 25 | img { 26 | width: 100%; 27 | } 28 | margin-bottom: 30px; 29 | } 30 | .title { 31 | font-size: 28px; 32 | } 33 | .detail { 34 | font-size: 18px; 35 | color: #999; 36 | margin-top: 16px; 37 | margin-bottom: 26px; 38 | } 39 | .action { 40 | font-family: Arial, serif; 41 | .like { 42 | margin-left: 20px; 43 | } 44 | } 45 | &:hover { 46 | box-shadow: 4px 4px 16px 0 #ccc; 47 | position: relative; 48 | top: -20px; 49 | left: -20px; 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/component/home/ExcellentProject/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import HomeTitle from '../HomeTitle'; 3 | import styles from './index.less'; 4 | import ep from 'assets/images/home/ep.png'; 5 | import { Icon } from 'antd'; 6 | 7 | export default function ExcellentProject(props) { 8 | return ( 9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 |

项目名称

17 |

项目描述

18 |

19 | 20 | 21 | 30000 22 | 23 | 24 | 25 | 30000 26 | 27 |

28 |
29 |
30 |
31 | 32 |
33 |

项目名称

34 |

项目描述

35 |

36 | 37 | 38 | 30000 39 | 40 | 41 | 42 | 30000 43 | 44 |

45 |
46 |
47 |
48 | 49 |
50 |

项目名称

51 |

项目描述

52 |

53 | 54 | 55 | 30000 56 | 57 | 58 | 59 | 30000 60 | 61 |

62 |
63 |
64 |
65 | 66 |
67 |

项目名称

68 |

项目描述

69 |

70 | 71 | 72 | 30000 73 | 74 | 75 | 76 | 30000 77 | 78 |

79 |
80 |
81 |
82 | ); 83 | } 84 | -------------------------------------------------------------------------------- /src/component/home/HomeTitle/index.less: -------------------------------------------------------------------------------- 1 | .cr-home-title { 2 | width: 100%; 3 | display: flex; 4 | justify-content: space-between; 5 | :global { 6 | .cr-home-title-text { 7 | font-size: 40px; 8 | height: 140px; 9 | text-align: left; 10 | line-height: 140px; 11 | } 12 | .cr-home-title-more { 13 | font-size: 30px; 14 | line-height: 140px; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/component/home/HomeTitle/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import router from 'umi/router'; 3 | import styles from './index.less'; 4 | 5 | type HomeTitleProps = { 6 | title: string; 7 | path?: string; 8 | color?: string; 9 | }; 10 | 11 | export default function(props: HomeTitleProps) { 12 | return ( 13 |
17 |
{props.title}
18 |
19 | { 21 | router.push(props.path); 22 | }} 23 | > 24 | {props.path ? '查看更多' : ''} 25 | 26 |
27 |
28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /src/component/user/Button.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Button from '@material-ui/core/Button'; 3 | import styles from './style.less'; 4 | 5 | export default class Index extends Component { 6 | render() { 7 | return ( 8 | 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/component/user/Input.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import DeleteForeverIcon from '@material-ui/icons/DeleteForever'; 3 | import styles from './style.less'; 4 | 5 | export default class Index extends Component { 6 | render() { 7 | const { label, type } = this.props; 8 | return ( 9 |
10 |

{label}

11 | 12 |
13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/component/user/Sign/index.less: -------------------------------------------------------------------------------- 1 | .sign-main { 2 | flex: 1; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | justify-content: center; 7 | height: calc(100% - 42px); 8 | box-sizing: border-box; 9 | 10 | :global { 11 | .sign-container{ 12 | background-color: #ffffff; 13 | width: 444px; 14 | margin: 0px auto; 15 | 16 | .sign-header { 17 | margin: 30px 0px 30px 0px; 18 | p{ 19 | margin: 20px auto 0px auto; 20 | font-size: 20px; 21 | font-family: "Adobe Heiti Std R"; 22 | font-weight: normal; 23 | color: rgba(24, 38, 42, 1); 24 | line-height: 26px; 25 | } 26 | } 27 | 28 | .sign-foot { 29 | background:rgba(246,246,246,1); 30 | padding: 38px 0px 40px 0px; 31 | color: #18262A; 32 | a { 33 | color: #40AEA8 34 | } 35 | } 36 | 37 | form { 38 | ::-webkit-input-placeholder { /* WebKit, Blink, Edge */ 39 | color: #FF40AEA8; 40 | font-weight: bold; 41 | } 42 | :-moz-placeholder { /* Mozilla Firefox 4 to 18 */ 43 | color: #FF40AEA8; 44 | opacity: 1; 45 | font-weight: bold; 46 | } 47 | ::-moz-placeholder { /* Mozilla Firefox 19+ */ 48 | color: #FF40AEA8; 49 | opacity: 1; 50 | font-weight: bold; 51 | } 52 | :-ms-input-placeholder { /* Internet Explorer 10-11 */ 53 | color: #FF40AEA8; 54 | font-weight: bold; 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/component/user/Sign/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import style from './index.less' 3 | import Logo from 'assets/images/login/logo.png' 4 | 5 | export default class Index extends React.Component { 6 | render() { 7 | const { header, children, footer } = this.props; 8 | return ( 9 |
10 |
11 |
12 | 13 |

{header}

14 |
15 | {children} 16 |
17 | {footer} 18 |
19 |
20 |
21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/component/user/style.less: -------------------------------------------------------------------------------- 1 | @import '../../assets/css/common/index'; 2 | .crInput { 3 | width: 440px; 4 | margin-top: 29px; 5 | 6 | .label { 7 | text-align: left; 8 | margin-bottom: 8px; 9 | font-size: 16px; 10 | } 11 | 12 | input { 13 | width: 440px; 14 | border: 1px solid #c1c1c1; 15 | padding: 14px; 16 | background: none; 17 | outline: none; 18 | } 19 | } 20 | 21 | .crButton { 22 | margin-top: 36px !important; 23 | width: 100%; 24 | border-radius: 0 !important; 25 | background-color: @primary-color!important; 26 | font-size: 16px !important; 27 | color: #fff !important; 28 | padding: 12px 0 !important; 29 | } 30 | -------------------------------------------------------------------------------- /src/global.less: -------------------------------------------------------------------------------- 1 | @import 'utils/nprogress/nprogress.css'; 2 | 3 | html, 4 | body, 5 | #root { 6 | height: 100%; 7 | } 8 | 9 | body { 10 | margin: 0; 11 | } 12 | 13 | button { 14 | cursor: pointer; 15 | } 16 | :global { 17 | p { 18 | margin: 0; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png'; 2 | declare module '*.svg'; 3 | declare module 'component/*'; 4 | -------------------------------------------------------------------------------- /src/layouts/BasicLayout/index.less: -------------------------------------------------------------------------------- 1 | .normal { 2 | font-family: Georgia, sans-serif; 3 | text-align: center; 4 | } 5 | 6 | .title { 7 | font-size: 2.5rem; 8 | font-weight: normal; 9 | letter-spacing: -1px; 10 | background: darkslateblue; 11 | padding: 0.6em 0; 12 | color: white; 13 | margin: 0; 14 | } 15 | 16 | .cr-base { 17 | width: 100%; 18 | //background: #ccc; 19 | min-height: 100vh; 20 | :global { 21 | .cr-main { 22 | width: 1220px; 23 | margin: 80px auto 0; 24 | background: #ffffff; 25 | height: 100%; 26 | min-width: 1220px; 27 | } 28 | @media (max-width: 1220px) { 29 | .cr-main { 30 | width: 100%; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/layouts/BasicLayout/index.tsx: -------------------------------------------------------------------------------- 1 | import styles from './index.less'; 2 | import { ComProps } from 'src/type/common'; 3 | import BasicHeader from 'component/common/BasicHeader/'; 4 | import BasicFooter from 'component/common/BasicFooter/'; 5 | 6 | export default function Index(props: ComProps) { 7 | return ( 8 |
9 | 10 |
11 | {props.children} 12 | 13 |
14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/layouts/DisplayLayout/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ComProps } from '../../type/common'; 3 | 4 | export default function Index(props: ComProps) { 5 | // console.log(props); 6 | return ( 7 |
8 |

Welcome to umi!

9 | {props.children} 10 |
11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /src/layouts/GlobalLayout/index.tsx: -------------------------------------------------------------------------------- 1 | import styles from '../BasicLayout/index.less'; 2 | import { ComProps } from '../../type/common'; 3 | // import MuiThemeProvider from 'material-ui' 4 | 5 | // const styles = require('./Index'); 6 | 7 | export default function Index(props: ComProps) { 8 | return
{props.children}
; 9 | } 10 | -------------------------------------------------------------------------------- /src/layouts/LoginLayout/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Grid from '@material-ui/core/Grid'; 3 | import styles from './style.less'; 4 | 5 | export default function LoginLayout(props) { 6 | return ( 7 |
8 | 9 | 10 |
{props.children}
11 |
12 | 13 |
14 | 15 | 16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/layouts/LoginLayout/style.less: -------------------------------------------------------------------------------- 1 | .cr-loginlayout { 2 | width: 100%; 3 | height: 100vh; 4 | 5 | .cr-login-container { 6 | height: 100vh; 7 | width: 560px; 8 | background: #fff; 9 | display: flex; 10 | align-items: center; 11 | justify-content: center; 12 | } 13 | 14 | .cr-login-bg { 15 | height: 100vh; 16 | width: 100%; 17 | background: url(assets/images/login/bgimg.png) no-repeat center center; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/layouts/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import BasicLayout from './BasicLayout/'; 3 | import DisplayLayout from './DisplayLayout/'; 4 | import GlobalLayout from './GlobalLayout/'; 5 | import LoginLayout from './LoginLayout/'; 6 | import './BasicLayout/index.less'; 7 | import { ComProps } from '../type/common'; 8 | import { isNull } from 'util'; 9 | 10 | export default function(props: ComProps) { 11 | const firstLevenPath = getSinglePath(props.location.pathname); 12 | let ChlLayout = null; 13 | switch (firstLevenPath) { 14 | case 'display': 15 | ChlLayout = () => {props.children}; 16 | break; 17 | case 'coderiver': 18 | ChlLayout = () => {props.children}; 19 | break; 20 | case 'user': 21 | ChlLayout = () => {props.children}; 22 | break; 23 | default: 24 | ChlLayout = null; 25 | break; 26 | } 27 | return ( 28 | 29 | {isNull(ChlLayout) ? <>{props.children} : {props.children}} 30 | 31 | ); 32 | } 33 | 34 | // 根据路由名称获取不同等级的路由 35 | export function getSinglePath(pathname = '/', level = 1) { 36 | const pathArr = pathname.split('/')[level]; 37 | if (pathArr) { 38 | return pathArr; 39 | } else { 40 | return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/layouts/typing.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.less'; 2 | -------------------------------------------------------------------------------- /src/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderiver-org/coderiver-react-pc/2ec0ba1bbb63524f5ed353a1d963f1e2fb8567ac/src/models/.gitkeep -------------------------------------------------------------------------------- /src/models/globalModel.tsx: -------------------------------------------------------------------------------- 1 | import { Model } from 'src/type/model'; 2 | 3 | type S = { 4 | test: number; 5 | }; 6 | 7 | export default ((): Model => { 8 | return { 9 | namespace: 'globalModel', 10 | 11 | state: { 12 | test: 0, 13 | }, 14 | 15 | subscriptions: { 16 | setup({ dispatch, history }) { 17 | // eslint-disable-line 18 | }, 19 | }, 20 | 21 | effects: { 22 | * fetch({ payload, callback }, { call, put }) { 23 | // eslint-disable-line 24 | yield put({ type: 'save' }); 25 | if (callback) callback(); 26 | }, 27 | }, 28 | 29 | reducers: { 30 | save({ state, action }) { 31 | return { ...state, ...action.payload }; 32 | }, 33 | }, 34 | }; 35 | })(); 36 | -------------------------------------------------------------------------------- /src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Redirect from 'umi/redirect'; 3 | 4 | export default class To404 extends React.Component { 5 | render() { 6 | return ; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/pages/coderiver/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component, ReactNode } from 'react'; 2 | import HomeTitle from 'component/home/HomeTitle'; 3 | import Banner from 'src/component/home/Banner'; 4 | import ExcellentProject from 'src/component/home/ExcellentProject'; 5 | import CodeRiverDownload from 'src/component/home/Download'; 6 | 7 | export default class Home extends Component { 8 | render(): ReactNode { 9 | return ( 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | ); 19 | } 20 | } 21 | 22 | // export default function Home() { 23 | // const [abc, setAbc] = React.useState('00000'); 24 | // return ( 25 | //
26 | //
{abc}
27 | // 28 | // 29 | // 30 | // 31 | // 32 | // 33 | //
34 | // ); 35 | // } 36 | -------------------------------------------------------------------------------- /src/pages/display/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { connect } from 'dva'; 3 | 4 | @connect(({ displayModel }) => ({ 5 | displayModel, 6 | })) 7 | export default class Display extends PureComponent { 8 | constructor(props) { 9 | super(props); 10 | } 11 | 12 | componentDidMount() { 13 | console.log(this); 14 | const dispatch = this.props.dispatch; 15 | dispatch({ 16 | type: 'displayModel/fetch', 17 | payload: { 18 | a: 1, 19 | }, 20 | }); 21 | } 22 | 23 | render() { 24 | return
login
; 25 | } 26 | } 27 | 28 | // export default function DisplayHooks(props) { 29 | // const [count, setCount] = useState(0); 30 | // /** 31 | // * useEffect 32 | // * 若第二个参数为空,则只会在mount和unmount执行, 33 | // * 注:为空数组和不传是有区别的 34 | // * 若不为空,则effect只会在第二个参数改变时执行, 35 | // * 若effect返回一个函数时,函数会在当前effect和下次effect之间执行,多用于解除事件绑定 36 | // */ 37 | // useEffect(() => { 38 | // document.title = `${count}`; 39 | // return () => { 40 | // // alert(111); 41 | // }; 42 | // }, []); 43 | // useCallback(() => {}, []); 44 | // // useContext(); 45 | // // useReducer(1,{count:1},3) 46 | // // useMemo(); 47 | // // useRef(); 48 | // // useImperativeMethods(); 49 | // // useLayoutEffect(); 50 | // // useMutationEffect() 51 | // return ( 52 | //
53 | // 54 | // 55 | //

{count}

56 | //
57 | // ); 58 | // } 59 | -------------------------------------------------------------------------------- /src/pages/display/models/displayModel.tsx: -------------------------------------------------------------------------------- 1 | import { Model } from 'src/type/model'; 2 | import { queryTest } from 'src/pages/display/service/displayService'; 3 | 4 | // type S = { 5 | // test: number; 6 | // }; 7 | 8 | export default ((): Model => { 9 | return { 10 | namespace: 'displayModel', 11 | 12 | state: { 13 | test: 0, 14 | }, 15 | 16 | subscriptions: { 17 | setup({ dispatch, history }) { 18 | // eslint-disable-line 19 | }, 20 | }, 21 | 22 | effects: { 23 | * fetch({ payload, callback }, { call, put }) { 24 | // eslint-disable-line 25 | const res = yield call(queryTest); 26 | console.log(res); 27 | yield put({ 28 | type: 'save', 29 | payload: { 30 | test: res, 31 | }, 32 | }); 33 | if (callback) callback(); 34 | }, 35 | }, 36 | 37 | reducers: { 38 | save(state, action) { 39 | return { ...state, ...action.payload }; 40 | }, 41 | }, 42 | }; 43 | })(); 44 | -------------------------------------------------------------------------------- /src/pages/display/service/displayService.tsx: -------------------------------------------------------------------------------- 1 | import request from 'src/utils/axios'; 2 | 3 | export async function queryTest() { 4 | return request({ 5 | url: `/test`, 6 | method: 'get', 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /src/pages/document.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 河码-CodeRiver 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/pages/exception/403.tsx: -------------------------------------------------------------------------------- 1 | import { ComProps } from 'src/type/common'; 2 | 3 | export default function Com403(props: ComProps) { 4 | return ( 5 |
6 |

Yay! Welcome to 403!

7 | {props.children} 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/pages/exception/404.tsx: -------------------------------------------------------------------------------- 1 | import { ComProps } from 'src/type/common'; 2 | 3 | export default function Com404(props: ComProps) { 4 | return ( 5 |
6 |

Yay! Welcome to 404!

7 | {props.children} 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/pages/exception/500.tsx: -------------------------------------------------------------------------------- 1 | import { ComProps } from 'src/type/common'; 2 | 3 | export default function Com500(props: ComProps) { 4 | return ( 5 |
6 |

Yay! Welcome to 500!

7 | {props.children} 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 注释路由 3 | * title:Index Page 4 | * Routes:- ./src/pages/display/index.tsx 5 | * - ./src/pages/display/index.tsx 6 | */ 7 | 8 | import React from 'react'; 9 | // import ButtonWithDefaultProps from './test/Button'; 10 | import Computed from './test/Computed'; 11 | import Link from 'umi/link'; 12 | import Redirect from 'umi/redirect'; 13 | import Button from '@material-ui/core/Button'; 14 | 15 | import teal from '@material-ui/core/colors/teal'; 16 | 17 | const primary = teal[500]; // #F44336 18 | 19 | import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'; 20 | 21 | const theme = createMuiTheme({ 22 | palette: { 23 | primary: { main: '#ff4400' }, 24 | }, 25 | }); 26 | 27 | // 根组件 28 | 29 | export default function() { 30 | // 留作权限验证判断跳转 31 | return ( 32 | 33 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/pages/less.css: -------------------------------------------------------------------------------- 1 | .normal { 2 | font-family: Georgia, sans-serif; 3 | margin-top: 4em; 4 | text-align: center; 5 | } 6 | 7 | .welcome { 8 | height: 328px; 9 | background: url(../assets/yay.jpg) no-repeat center 0; 10 | background-size: 388px 328px; 11 | } 12 | 13 | .list { 14 | font-size: 1.2em; 15 | margin-top: 1.8em; 16 | list-style: none; 17 | line-height: 1.5em; 18 | } 19 | 20 | .list code { 21 | background: #f7f7f7; 22 | } 23 | -------------------------------------------------------------------------------- /src/pages/test/Button.tsx: -------------------------------------------------------------------------------- 1 | import React, { MouseEvent, SFC, ComponentType, Component } from 'react'; 2 | 3 | /*type Props = { 4 | onClick(e: MouseEvent): void 5 | children:ReactNode 6 | }; 7 | const Button = ({ onClick: handleClick, children }:Props) => ( 8 | 9 | );*/ 10 | 11 | export const withDefaultProps =

= Partial

>( 12 | defaultProps: DP, 13 | Cmp: ComponentType

14 | ) => { 15 | // 提取出必须的属性 16 | type RequiredProps = Partial

; 17 | // 重新创建我们的属性定义,通过一个相交类型,将所有的原始属性标记成可选的,必选属性标记成可选的 18 | type Props = Partial & Required; 19 | Cmp.defaultProps = defaultProps; 20 | 21 | return (Cmp as ComponentType) as ComponentType; 22 | }; 23 | 24 | const defaultProps = { color: 'red' }; 25 | 26 | type DefaultProps = typeof defaultProps; 27 | 28 | type Props = { onClick(e: MouseEvent): void } & DefaultProps; 29 | // SFC (interface StatelessComponent

) 含有预定义的children 和 30 | // (defaultProps,displayName等等...) 31 | const Button: SFC = ({ onClick: handleClick, children, color }) => ( 32 | 41 | ); 42 | 43 | const ButtonWithDefaultProps = withDefaultProps(defaultProps, Button); 44 | 45 | const ButtonWithDefaultProps1 = withDefaultProps( 46 | defaultProps, 47 | ({ onClick: handleClick, children, color }) => ( 48 | 57 | ) 58 | ); 59 | 60 | const ButtonWithDefaultProps2 = withDefaultProps( 61 | defaultProps, 62 | class Buttons extends Component { 63 | render() { 64 | const { onClick: handleClick, children, color } = this.props; 65 | return ( 66 | 75 | ); 76 | } 77 | } 78 | ); 79 | 80 | export default ButtonWithDefaultProps; 81 | -------------------------------------------------------------------------------- /src/pages/test/Computed.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { default as Button } from './Button'; 3 | 4 | const initialState = { clicksCount: 0 }; 5 | type State = Readonly; 6 | 7 | const incrementClicksCount = (prevState: State) => ({ 8 | clicksCount: prevState.clicksCount + 1, 9 | }); 10 | const decrementClicksCount = (prevState: State) => ({ 11 | clicksCount: prevState.clicksCount - 1, 12 | }); 13 | 14 | // 参数语义化 15 | const test: (name: string, age: number) => number = function(n, a) { 16 | return a; 17 | }; 18 | test('lsc', 256); 19 | 20 | export default class Computed extends Component { 21 | readonly state: State = initialState; 22 | 23 | /* doBadThings = () => { 24 | this.state = { clicksCount: 12 }; 25 | this.state.clicksCount = 123; 26 | }; */ 27 | private handleIncrement = () => this.setState(incrementClicksCount); 28 | private handleDecrement = () => this.setState(decrementClicksCount); 29 | 30 | render() { 31 | const { clicksCount } = this.state; 32 | return ( 33 | <> 34 |

{clicksCount}

35 |

36 | 39 |

40 |

41 | 44 |

45 | 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/pages/test/Menu.tsx: -------------------------------------------------------------------------------- 1 | import { Component, SFC } from 'react'; 2 | import Toggleable, { ToggleableComponentProps } from './Toggleable'; 3 | 4 | type MenuItemProps = { title: string }; 5 | const MenuItem: SFC = ({ 6 | title, 7 | toggle, 8 | show, 9 | children, 10 | }) => ( 11 | <> 12 |
13 |

{title}

14 |
15 | {show ? children : null} 16 | 17 | ); 18 | 19 | type Props = { title: string }; 20 | const ToggleableMenu: SFC = ({ title, children }) => ( 21 | ( 23 | 24 | {children} 25 | 26 | )} 27 | /> 28 | ); 29 | 30 | const ToggleableWithTitle = Toggleable.ofType(); 31 | 32 | const ToggleableMenuViaComponentInjection: SFC = ({ title, children }) => ( 33 | 34 | {children} 35 | 36 | ); 37 | 38 | export default class Menu extends Component { 39 | render() { 40 | return ( 41 | <> 42 | 123 43 | 456 44 | 789 45 | 46 | 123 47 | 48 | 49 | 456 50 | 51 | 52 | 789 53 | 54 | 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/pages/test/Toggleable.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component, MouseEvent, ReactNode, ComponentType } from 'react'; 2 | import { 3 | isFunction, 4 | // getHocComponentName 5 | } from 'util'; 6 | 7 | const initialState = { 8 | show: false, 9 | }; 10 | 11 | type State = Readonly; 12 | type DefaultProps

= { props: P }; 13 | const defaultProps: DefaultProps = { props: {} }; 14 | 15 | type Props

= Partial< 16 | { 17 | children: RenderCallback | ReactNode; 18 | render: RenderCallback; 19 | component: ComponentType>; 20 | } & DefaultProps

21 | >; 22 | 23 | type RenderCallback = (args: ToggleableComponentProps) => JSX.Element; 24 | 25 | export type ToggleableComponentProps

= { 26 | show: State['show']; 27 | toggle: Toggleable['toggle']; 28 | } & P; 29 | 30 | const updateShowState = (prevState: State) => ({ show: !prevState.show }); 31 | 32 | export default class Toggleable extends Component { 33 | static readonly defaultProps: Props = defaultProps; 34 | 35 | static ofType() { 36 | return Toggleable; 37 | // as Constructor>; 38 | } 39 | 40 | readonly state: State = initialState; 41 | 42 | private toggle = (event: MouseEvent) => { 43 | this.setState(updateShowState); 44 | }; 45 | 46 | render() { 47 | const { children, render, component: InjectComponent, props } = this.props; 48 | const renderProps = { show: this.state.show, toggle: this.toggle }; 49 | 50 | if (render) { 51 | return render(renderProps); 52 | } 53 | 54 | if (InjectComponent) { 55 | return ( 56 | 57 | {children} 58 | 59 | ); 60 | } 61 | 62 | // return isFunction(children) ? children(renderProps) : null; 63 | return isFunction(children) ? children : null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/pages/user/login/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import Input from 'component/user/Input'; 4 | import Button from 'component/user/Button'; 5 | import Checkbox from '@material-ui/core/Checkbox'; 6 | import Link from '@material-ui/core/Link'; 7 | 8 | import styles from '../style.less'; 9 | export default class Index extends Component { 10 | render() { 11 | return ( 12 |

13 |
14 |

登录

15 |

16 | 还没有账户?创建新账户 17 |

18 | 19 | 20 |
29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/pages/user/register/form.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Input, 4 | InputAdornment, 5 | IconButton, 6 | Button, 7 | FormControl, 8 | Select, 9 | MenuItem, 10 | InputLabel, 11 | StyleRulesCallback, 12 | } from '@material-ui/core'; 13 | import { StyleRules, withStyles } from '@material-ui/core/styles'; 14 | import { Visibility, VisibilityOff } from '@material-ui/icons'; 15 | 16 | export interface Props { 17 | classes: { [key: string]: string }; 18 | } 19 | 20 | interface State { 21 | showPassword: boolean; 22 | showEnterPassword: boolean; 23 | params: { 24 | [key: string]: any; 25 | }; 26 | sendCode: boolean; 27 | [key: string]: any; 28 | } 29 | 30 | const StyledSelect = withStyles({ 31 | icon: { 32 | display: 'none', 33 | }, 34 | })(Select); 35 | 36 | const styles = theme => ({ 37 | form: { 38 | padding: '0px 50px 50px 50px', 39 | }, 40 | formControl: { 41 | minWidth: 120, 42 | width: '100%', 43 | }, 44 | formSelectControl: { 45 | width: 'calc(50% - 6px)', 46 | }, 47 | formLeftSelectControl: { 48 | marginRight: 6, 49 | }, 50 | formRightSelectControl: { 51 | marginLeft: 6, 52 | }, 53 | input: { 54 | height: 60, 55 | marginTop: '0px !important', 56 | icon: { 57 | fontSize: 40, 58 | }, 59 | }, 60 | button: { 61 | minWidth: 115, 62 | TextAlign: 'right', 63 | // textAlign: 'right', 64 | color: '#FF40AEA8', 65 | }, 66 | submitButton: { 67 | marginTop: 50, 68 | borderRadius: 0, 69 | color: '#FFFFFF', 70 | width: '100%', 71 | backgroundColor: '#40AEA8', 72 | fontSize: 20, 73 | }, 74 | }); 75 | class RegisterForm extends React.Component { 76 | constructor(props: Props) { 77 | super(props); 78 | this.state = { 79 | showPassword: false, 80 | showEnterPassword: false, 81 | sendCode: false, 82 | params: { 83 | exp: '', 84 | role: '', 85 | }, 86 | }; 87 | } 88 | 89 | handleSubmit = e => { 90 | e.preventDefault(); 91 | console.log(this.state.params); 92 | }; 93 | 94 | sendCode = () => { 95 | this.setState({ 96 | sendCode: true, 97 | }); 98 | }; 99 | 100 | handleClickShowPassword(name: string) { 101 | // eslint:disable // 102 | this.setState({ 103 | [name]: !this.state[name], 104 | }); 105 | } 106 | 107 | inputChange = e => { 108 | const { name, value } = e.target; 109 | this.setState({ 110 | params: Object.assign({}, this.state.params, { [name]: value }), 111 | }); 112 | }; 113 | 114 | render() { 115 | const { classes } = this.props; 116 | const { showPassword, showEnterPassword, sendCode, params } = this.state; 117 | const { role, exp } = params; 118 | return ( 119 |
120 |
121 | 122 | 128 | 129 | 130 | {`${ 137 | sendCode ? '重新' : '' 138 | }获取验证码`} 139 | } 140 | /> 141 | 142 | 143 | 151 | 152 | {showPassword ? : } 153 | 154 | 155 | } 156 | /> 157 | 158 | 159 | 167 | 170 | {showEnterPassword ? : } 171 | 172 | 173 | } 174 | /> 175 | 176 | 177 | 183 | 184 | 185 | {role ? null : 选择角色} 186 | 193 | 产品经理 194 | 设计师 195 | 前端工程师 196 | 移动端端工程师 197 | 小程序 198 | 199 | 200 | 203 | {exp ? null : 工作经验} 204 | 211 | 0-3年 212 | 3-5年 213 | 5-9年 214 | 10年以上 215 | 216 | 217 | 220 |
221 |
222 | ); 223 | } 224 | } 225 | 226 | export default withStyles(styles)(RegisterForm); 227 | 228 | // tslint:disable //——忽略该行以下所有代码出现的错误提示 229 | // tslint:enable //——当前ts文件重新启用tslint 230 | // tslint:disable-line——忽略当前行代码出现的错误提示 231 | // tslint:disable-next-line——忽略下一行代码出现的错误提示 232 | -------------------------------------------------------------------------------- /src/pages/user/register/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Sign from 'component/user/Sign'; 3 | import RegisterForm, { Props } from './form'; 4 | 5 | type State = any 6 | 7 | export default class Index extends React.Component { 8 | render() { 9 | const { classes } = this.props; 10 | const header = '欢迎加入CodeRiver'; 11 | const footer = ( 12 | 已有账号?登录 13 | ); 14 | return ( 15 | 18 | 19 | 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/pages/user/style.less: -------------------------------------------------------------------------------- 1 | .logo { 2 | width: 221px; 3 | height: 128px; 4 | background: url(assets/images/login/logo.jpg) no-repeat center 0; 5 | background-size: 100% 100%; 6 | margin: 0 auto; 7 | margin-top: -40px; 8 | } 9 | 10 | .title { 11 | font-size: 48px; 12 | font-weight: 200; 13 | margin: 5px 2px 11px 0; 14 | } 15 | 16 | .subTitle { 17 | font-size: 20px; 18 | text-indent: 2px; 19 | letter-spacing: 1px; 20 | } 21 | 22 | .link { 23 | color: #0194a3 !important; 24 | } 25 | 26 | .loginFotter { 27 | font-size: 16px; 28 | margin-top: 16px; 29 | span.remberPwd { 30 | display: inline-block; 31 | height: 48px; 32 | line-height: 50px; 33 | vertical-align: middle; 34 | } 35 | .link { 36 | text-decoration: underline; 37 | float: right; 38 | margin-top: 12px; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/type/common.d.ts: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export type ComProps = { 4 | children?: ReactNode; 5 | location?: any; 6 | }; 7 | 8 | -------------------------------------------------------------------------------- /src/type/model.d.ts: -------------------------------------------------------------------------------- 1 | import { AnyAction, Dispatch, Reducer } from 'redux'; 2 | import { History } from 'history'; 3 | 4 | export interface ReducersMapObject { 5 | [key: string]: (api: ReducerPayload) => T; 6 | } 7 | 8 | export type Effect = (action: AnyAction, effects: EffectsCommandMap) => void; 9 | export type EffectType = 'takeEvery' | 'takeLatest' | 'watcher' | 'throttle'; 10 | export type EffectWithType = [Effect, { type: EffectType }]; 11 | export type Subscription = (api: SubscriptionAPI, done: Function) => void; 12 | export type ReducersMapObjectWithEnhancer = [ReducersMapObject, ReducerEnhancer]; 13 | 14 | export interface ReducerEnhancer { 15 | (reducer: Reducer): void; 16 | } 17 | 18 | export interface EffectsCommandMap { 19 | put: (action: A) => any; 20 | call: Function; 21 | select: Function; 22 | take: Function; 23 | cancel: Function; 24 | 25 | [key: string]: any; 26 | } 27 | 28 | export interface MyReducer extends AnyAction { 29 | // type: string; 30 | // payload?: object; 31 | } 32 | 33 | export interface ReducerPayload { 34 | state: T; 35 | action: MyReducer; 36 | } 37 | 38 | export interface EffectsPayload { 39 | callback: Function; 40 | payload: T; 41 | } 42 | 43 | export interface EffectsMapObject { 44 | [key: string]: (payload: EffectsPayload, saga: EffectsCommandMap) => void; 45 | } 46 | 47 | export interface SubscriptionAPI { 48 | history: History; 49 | dispatch: Dispatch; 50 | } 51 | 52 | export interface SubscriptionsMapObject { 53 | [key: string]: Subscription; 54 | } 55 | 56 | export interface Model { 57 | namespace: string; 58 | state?: T; 59 | reducers?: ReducersMapObject | ReducersMapObjectWithEnhancer | any; 60 | effects?: EffectsMapObject | EffectWithType; 61 | subscriptions?: SubscriptionsMapObject; 62 | } 63 | -------------------------------------------------------------------------------- /src/utils/axios.tsx: -------------------------------------------------------------------------------- 1 | // request.js 2 | import Axios from 'axios'; 3 | import NProgress from 'nprogress'; 4 | import { notification, message } from 'antd'; 5 | import router from 'umi/router'; 6 | import { Promise } from 'q'; 7 | 8 | const axios = Axios; 9 | 10 | /** 11 | * 一、功能: 12 | * 1. 统一拦截http错误请求码; 13 | * 2. 统一拦截业务错误代码; 14 | * 3. 统一设置请求前缀 15 | * |-- 每个 http 加前缀 baseURL = /api/v1,从配置文件中获取 apiPrefix 16 | * 4. 配置异步请求过渡状态:显示蓝色加载条表示正在请求中,避免给用户页面假死的不好体验。 17 | * |-- 使用 NProgress 工具库。 18 | * 19 | * 二、引包: 20 | * |-- axios:http 请求工具库 21 | * |-- NProgress:异步请求过度条,在浏览器主体部分顶部显示蓝色小条 22 | * |-- notification:Antd组件 > 处理错误响应码提示信息 23 | * |-- routerRedux:dva/router对象,用于路由跳转,错误响应码跳转相应页面 24 | * |-- store:dva中对象,使用里面的 dispatch 对象,用于触发路由跳转 25 | */ 26 | 27 | // 设置全局参数,如响应超市时间,请求前缀等。 28 | axios.defaults.timeout = 5000; 29 | axios.defaults.baseURL = '/api/v1'; 30 | axios.defaults.withCredentials = true; 31 | 32 | // 添加一个请求拦截器,用于设置请求过渡状态 33 | axios.interceptors.request.use( 34 | config => { 35 | // 请求开始,蓝色过渡滚动条开始出现 36 | NProgress.start(); 37 | return config; 38 | }, 39 | error => { 40 | // return Promise.reject(error); 41 | return Promise(error); 42 | } 43 | ); 44 | 45 | // 添加一个返回拦截器 46 | axios.interceptors.response.use( 47 | response => { 48 | // 请求结束,蓝色过渡滚动条消失 49 | NProgress.done(); 50 | return response; 51 | }, 52 | error => { 53 | // 请求结束,蓝色过渡滚动条消失 54 | // 即使出现异常,也要调用关闭方法,否则一直处于加载状态很奇怪 55 | NProgress.done(); 56 | // return Promise.reject(error); 57 | return Promise(error); 58 | } 59 | ); 60 | 61 | export default function request(opt) { 62 | // console.log(opt); 63 | // 调用 axios api,统一拦截 64 | return axios(opt) 65 | .then(response => { 66 | // >>>>>>>>>>>>>> 请求成功 <<<<<<<<<<<<<< 67 | console.log(`【${opt.method} ${opt.url}】请求成功,响应数据:%o`, response.data); 68 | 69 | // 打印业务错误提示 70 | console.log(response.data.code); 71 | if (response.data && response.data.code != '0000') { 72 | message.error(response.data.message); 73 | } 74 | 75 | return { ...response.data }; 76 | }) 77 | .catch(error => { 78 | // >>>>>>>>>>>>>> 请求失败 <<<<<<<<<<<<<< 79 | // 请求配置发生的错误 80 | if (!error.response) { 81 | return console.log('Error', error.message); 82 | } 83 | 84 | // 响应时状态码处理 85 | const status = error.response.status; 86 | const errortext = codeMessage[status] || error.response.statusText; 87 | 88 | notification.error({ 89 | message: `请求错误 ${status}`, 90 | description: errortext, 91 | }); 92 | 93 | // 存在请求,但是服务器的返回一个状态码,它们都在2xx之外 94 | // const { dispatch } = window.g_app._store; 95 | 96 | if (status === 401) { 97 | // dispatch(routerRedux.push('/user/login')); 98 | router.push('/user/login'); 99 | } else if (status === 403) { 100 | router.push('/exception/403'); 101 | } else if (status <= 504 && status >= 500) { 102 | router.push('/exception/500'); 103 | } else if (status >= 404 && status < 422) { 104 | router.push('/exception/404'); 105 | } 106 | 107 | // 开发时使用,上线时删除 108 | console.log(`【${opt.method} ${opt.url}】请求失败,响应数据:%o`, error.response); 109 | 110 | return { code: status, message: errortext }; 111 | }); 112 | } 113 | 114 | // 状态码错误信息 115 | const codeMessage = { 116 | 200: '服务器成功返回请求的数据。', 117 | 201: '新建或修改数据成功。', 118 | 202: '一个请求已经进入后台排队(异步任务)。', 119 | 204: '删除数据成功。', 120 | 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。', 121 | 401: '用户没有权限(令牌、用户名、密码错误)。', 122 | 403: '用户得到授权,但是访问是被禁止的。', 123 | 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。', 124 | 406: '请求的格式不可得。', 125 | 410: '请求的资源被永久删除,且不会再得到的。', 126 | 422: '当创建一个对象时,发生一个验证错误。', 127 | 500: '服务器发生错误,请检查服务器。', 128 | 502: '网关错误。', 129 | 503: '服务不可用,服务器暂时过载或维护。', 130 | 504: '网关超时。', 131 | }; 132 | -------------------------------------------------------------------------------- /src/utils/nprogress/nprogress.css: -------------------------------------------------------------------------------- 1 | /* Make clicks pass-through */ 2 | #nprogress { 3 | pointer-events: none; 4 | } 5 | 6 | #nprogress .bar { 7 | background: #29d; 8 | 9 | position: fixed; 10 | z-index: 1031; 11 | top: 0; 12 | left: 0; 13 | 14 | width: 100%; 15 | height: 2px; 16 | } 17 | 18 | /* Fancy blur effect */ 19 | #nprogress .peg { 20 | display: block; 21 | position: absolute; 22 | right: 0px; 23 | width: 100px; 24 | height: 100%; 25 | box-shadow: 0 0 10px #29d, 0 0 5px #29d; 26 | opacity: 1.0; 27 | 28 | -webkit-transform: rotate(3deg) translate(0px, -4px); 29 | -ms-transform: rotate(3deg) translate(0px, -4px); 30 | transform: rotate(3deg) translate(0px, -4px); 31 | } 32 | 33 | /* Remove these to get rid of the spinner */ 34 | #nprogress .spinner { 35 | display: block; 36 | position: fixed; 37 | z-index: 1031; 38 | top: 15px; 39 | right: 15px; 40 | } 41 | 42 | #nprogress .spinner-icon { 43 | width: 18px; 44 | height: 18px; 45 | box-sizing: border-box; 46 | 47 | border: solid 2px transparent; 48 | border-top-color: #29d; 49 | border-left-color: #29d; 50 | border-radius: 50%; 51 | 52 | -webkit-animation: nprogress-spinner 400ms linear infinite; 53 | animation: nprogress-spinner 400ms linear infinite; 54 | } 55 | 56 | .nprogress-custom-parent { 57 | overflow: hidden; 58 | position: relative; 59 | } 60 | 61 | .nprogress-custom-parent #nprogress .spinner, 62 | .nprogress-custom-parent #nprogress .bar { 63 | position: absolute; 64 | } 65 | 66 | @-webkit-keyframes nprogress-spinner { 67 | 0% { -webkit-transform: rotate(0deg); } 68 | 100% { -webkit-transform: rotate(360deg); } 69 | } 70 | @keyframes nprogress-spinner { 71 | 0% { transform: rotate(0deg); } 72 | 100% { transform: rotate(360deg); } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/utils/nprogress/nprogress.js: -------------------------------------------------------------------------------- 1 | /* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress 2 | * @license MIT */ 3 | 4 | (function(root, factory) { 5 | if (typeof define === 'function' && define.amd) { 6 | define(factory); 7 | } else if (typeof exports === 'object') { 8 | module.exports = factory(); 9 | } else { 10 | root.NProgress = factory(); 11 | } 12 | })(this, function() { 13 | var NProgress = {}; 14 | 15 | NProgress.version = '0.2.0'; 16 | 17 | var Settings = (NProgress.settings = { 18 | minimum: 0.08, 19 | easing: 'ease', 20 | positionUsing: '', 21 | speed: 200, 22 | trickle: true, 23 | trickleRate: 0.02, 24 | trickleSpeed: 800, 25 | showSpinner: true, 26 | barSelector: '[role="bar"]', 27 | spinnerSelector: '[role="spinner"]', 28 | parent: 'body', 29 | template: 30 | '
', 31 | }); 32 | 33 | /** 34 | * Updates configuration. 35 | * 36 | * NProgress.configure({ 37 | * minimum: 0.1 38 | * }); 39 | */ 40 | NProgress.configure = function(options) { 41 | var key, 42 | value; 43 | for (key in options) { 44 | if (Object.prototype.hasOwnProperty.call(options, key)) { 45 | value = options[key]; 46 | if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value; 47 | } 48 | } 49 | 50 | return this; 51 | }; 52 | 53 | /** 54 | * Last number. 55 | */ 56 | 57 | NProgress.status = null; 58 | 59 | /** 60 | * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`. 61 | * 62 | * NProgress.set(0.4); 63 | * NProgress.set(1.0); 64 | */ 65 | 66 | NProgress.set = function(n) { 67 | var started = NProgress.isStarted(); 68 | 69 | n = clamp(n, Settings.minimum, 1); 70 | NProgress.status = n === 1 ? null : n; 71 | 72 | var progress = NProgress.render(!started), 73 | bar = progress.querySelector(Settings.barSelector), 74 | speed = Settings.speed, 75 | ease = Settings.easing; 76 | 77 | progress.offsetWidth; /* Repaint */ 78 | 79 | queue(function(next) { 80 | // Set positionUsing if it hasn't already been set 81 | if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS(); 82 | 83 | // Add transition 84 | css(bar, barPositionCSS(n, speed, ease)); 85 | 86 | if (n === 1) { 87 | // Fade out 88 | css(progress, { 89 | transition: 'none', 90 | opacity: 1, 91 | }); 92 | progress.offsetWidth; /* Repaint */ 93 | 94 | setTimeout(function() { 95 | css(progress, { 96 | transition: 'all ' + speed + 'ms linear', 97 | opacity: 0, 98 | }); 99 | setTimeout(function() { 100 | NProgress.remove(); 101 | next(); 102 | }, speed); 103 | }, speed); 104 | } else { 105 | setTimeout(next, speed); 106 | } 107 | }); 108 | 109 | return this; 110 | }; 111 | 112 | NProgress.isStarted = function() { 113 | return typeof NProgress.status === 'number'; 114 | }; 115 | 116 | /** 117 | * Shows the progress bar. 118 | * This is the same as setting the status to 0%, except that it doesn't go backwards. 119 | * 120 | * NProgress.start(); 121 | * 122 | */ 123 | NProgress.start = function() { 124 | if (!NProgress.status) NProgress.set(0); 125 | 126 | var work = function() { 127 | setTimeout(function() { 128 | if (!NProgress.status) return; 129 | NProgress.trickle(); 130 | work(); 131 | }, Settings.trickleSpeed); 132 | }; 133 | 134 | if (Settings.trickle) work(); 135 | 136 | return this; 137 | }; 138 | 139 | /** 140 | * Hides the progress bar. 141 | * This is the *sort of* the same as setting the status to 100%, with the 142 | * difference being `done()` makes some placebo effect of some realistic motion. 143 | * 144 | * NProgress.done(); 145 | * 146 | * If `true` is passed, it will show the progress bar even if its hidden. 147 | * 148 | * NProgress.done(true); 149 | */ 150 | 151 | NProgress.done = function(force) { 152 | if (!force && !NProgress.status) return this; 153 | 154 | return NProgress.inc(0.3 + 0.5 * Math.random()).set(1); 155 | }; 156 | 157 | /** 158 | * Increments by a random amount. 159 | */ 160 | 161 | NProgress.inc = function(amount) { 162 | var n = NProgress.status; 163 | 164 | if (!n) { 165 | return NProgress.start(); 166 | } else { 167 | if (typeof amount !== 'number') { 168 | amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95); 169 | } 170 | 171 | n = clamp(n + amount, 0, 0.994); 172 | return NProgress.set(n); 173 | } 174 | }; 175 | 176 | NProgress.trickle = function() { 177 | return NProgress.inc(Math.random() * Settings.trickleRate); 178 | }; 179 | 180 | /** 181 | * Waits for all supplied jQuery promises and 182 | * increases the progress as the promises resolve. 183 | * 184 | * @param $promise jQUery Promise 185 | */ 186 | (function() { 187 | var initial = 0, 188 | current = 0; 189 | 190 | NProgress.promise = function($promise) { 191 | if (!$promise || $promise.state() === 'resolved') { 192 | return this; 193 | } 194 | 195 | if (current === 0) { 196 | NProgress.start(); 197 | } 198 | 199 | initial++; 200 | current++; 201 | 202 | $promise.always(function() { 203 | current--; 204 | if (current === 0) { 205 | initial = 0; 206 | NProgress.done(); 207 | } else { 208 | NProgress.set((initial - current) / initial); 209 | } 210 | }); 211 | 212 | return this; 213 | }; 214 | })(); 215 | 216 | /** 217 | * (Internal) renders the progress bar markup based on the `template` 218 | * setting. 219 | */ 220 | 221 | NProgress.render = function(fromStart) { 222 | if (NProgress.isRendered()) return document.getElementById('nprogress'); 223 | 224 | addClass(document.documentElement, 'nprogress-busy'); 225 | 226 | var progress = document.createElement('div'); 227 | progress.id = 'nprogress'; 228 | progress.innerHTML = Settings.template; 229 | 230 | var bar = progress.querySelector(Settings.barSelector), 231 | perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0), 232 | parent = document.querySelector(Settings.parent), 233 | spinner; 234 | 235 | css(bar, { 236 | transition: 'all 0 linear', 237 | transform: 'translate3d(' + perc + '%,0,0)', 238 | }); 239 | 240 | if (!Settings.showSpinner) { 241 | spinner = progress.querySelector(Settings.spinnerSelector); 242 | spinner && removeElement(spinner); 243 | } 244 | 245 | if (parent != document.body) { 246 | addClass(parent, 'nprogress-custom-parent'); 247 | } 248 | 249 | parent.appendChild(progress); 250 | return progress; 251 | }; 252 | 253 | /** 254 | * Removes the element. Opposite of render(). 255 | */ 256 | 257 | NProgress.remove = function() { 258 | removeClass(document.documentElement, 'nprogress-busy'); 259 | removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent'); 260 | var progress = document.getElementById('nprogress'); 261 | progress && removeElement(progress); 262 | }; 263 | 264 | /** 265 | * Checks if the progress bar is rendered. 266 | */ 267 | 268 | NProgress.isRendered = function() { 269 | return !!document.getElementById('nprogress'); 270 | }; 271 | 272 | /** 273 | * Determine which positioning CSS rule to use. 274 | */ 275 | 276 | NProgress.getPositioningCSS = function() { 277 | // Sniff on document.body.style 278 | var bodyStyle = document.body.style; 279 | 280 | // Sniff prefixes 281 | var vendorPrefix = 282 | 'WebkitTransform' in bodyStyle 283 | ? 'Webkit' 284 | : 'MozTransform' in bodyStyle 285 | ? 'Moz' 286 | : 'msTransform' in bodyStyle 287 | ? 'ms' 288 | : 'OTransform' in bodyStyle 289 | ? 'O' 290 | : ''; 291 | 292 | if (vendorPrefix + 'Perspective' in bodyStyle) { 293 | // Modern browsers with 3D support, e.g. Webkit, IE10 294 | return 'translate3d'; 295 | } else if (vendorPrefix + 'Transform' in bodyStyle) { 296 | // Browsers without 3D support, e.g. IE9 297 | return 'translate'; 298 | } else { 299 | // Browsers without translate() support, e.g. IE7-8 300 | return 'margin'; 301 | } 302 | }; 303 | 304 | /** 305 | * Helpers 306 | */ 307 | 308 | function clamp(n, min, max) { 309 | if (n < min) return min; 310 | if (n > max) return max; 311 | return n; 312 | } 313 | 314 | /** 315 | * (Internal) converts a percentage (`0..1`) to a bar translateX 316 | * percentage (`-100%..0%`). 317 | */ 318 | 319 | function toBarPerc(n) { 320 | return (-1 + n) * 100; 321 | } 322 | 323 | /** 324 | * (Internal) returns the correct CSS for changing the bar's 325 | * position given an n percentage, and speed and ease from Settings 326 | */ 327 | 328 | function barPositionCSS(n, speed, ease) { 329 | var barCSS; 330 | 331 | if (Settings.positionUsing === 'translate3d') { 332 | barCSS = { transform: 'translate3d(' + toBarPerc(n) + '%,0,0)' }; 333 | } else if (Settings.positionUsing === 'translate') { 334 | barCSS = { transform: 'translate(' + toBarPerc(n) + '%,0)' }; 335 | } else { 336 | barCSS = { 'margin-left': toBarPerc(n) + '%' }; 337 | } 338 | 339 | barCSS.transition = 'all ' + speed + 'ms ' + ease; 340 | 341 | return barCSS; 342 | } 343 | 344 | /** 345 | * (Internal) Queues a function to be executed. 346 | */ 347 | 348 | var queue = (function() { 349 | var pending = []; 350 | 351 | function next() { 352 | var fn = pending.shift(); 353 | if (fn) { 354 | fn(next); 355 | } 356 | } 357 | 358 | return function(fn) { 359 | pending.push(fn); 360 | if (pending.length == 1) next(); 361 | }; 362 | })(); 363 | 364 | /** 365 | * (Internal) Applies css properties to an element, similar to the jQuery 366 | * css method. 367 | * 368 | * While this helper does assist with vendor prefixed property names, it 369 | * does not perform any manipulation of values prior to setting styles. 370 | */ 371 | 372 | var css = (function() { 373 | var cssPrefixes = ['Webkit', 'O', 'Moz', 'ms'], 374 | cssProps = {}; 375 | 376 | function camelCase(string) { 377 | return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) { 378 | return letter.toUpperCase(); 379 | }); 380 | } 381 | 382 | function getVendorProp(name) { 383 | var style = document.body.style; 384 | if (name in style) return name; 385 | 386 | var i = cssPrefixes.length, 387 | capName = name.charAt(0).toUpperCase() + name.slice(1), 388 | vendorName; 389 | while (i--) { 390 | vendorName = cssPrefixes[i] + capName; 391 | if (vendorName in style) return vendorName; 392 | } 393 | 394 | return name; 395 | } 396 | 397 | function getStyleProp(name) { 398 | name = camelCase(name); 399 | return cssProps[name] || getVendorProp(name); 400 | } 401 | 402 | function applyCss(element, prop, value) { 403 | prop = getStyleProp(prop); 404 | element.style[prop] = value; 405 | } 406 | 407 | return function(element, properties) { 408 | var args = arguments, 409 | prop, 410 | value; 411 | 412 | if (args.length == 2) { 413 | for (prop in properties) { 414 | if (Object.prototype.hasOwnProperty.call(prop, properties)) { 415 | value = properties[prop]; 416 | if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value); 417 | } 418 | } 419 | } else { 420 | applyCss(element, args[1], args[2]); 421 | } 422 | }; 423 | })(); 424 | 425 | /** 426 | * (Internal) Determines if an element or space separated list of class names contains a class name. 427 | */ 428 | 429 | function hasClass(element, name) { 430 | var list = typeof element == 'string' ? element : classList(element); 431 | return list.indexOf(' ' + name + ' ') >= 0; 432 | } 433 | 434 | /** 435 | * (Internal) Adds a class to an element. 436 | */ 437 | 438 | function addClass(element, name) { 439 | var oldList = classList(element), 440 | newList = oldList + name; 441 | 442 | if (hasClass(oldList, name)) return; 443 | 444 | // Trim the opening space. 445 | element.className = newList.substring(1); 446 | } 447 | 448 | /** 449 | * (Internal) Removes a class from an element. 450 | */ 451 | 452 | function removeClass(element, name) { 453 | var oldList = classList(element), 454 | newList; 455 | 456 | if (!hasClass(element, name)) return; 457 | 458 | // Replace the class name. 459 | newList = oldList.replace(' ' + name + ' ', ' '); 460 | 461 | // Trim the opening and closing spaces. 462 | element.className = newList.substring(1, newList.length - 1); 463 | } 464 | 465 | /** 466 | * (Internal) Gets a space separated list of the class names on the element. 467 | * The list is wrapped with a single space on each end to facilitate finding 468 | * matches within the list. 469 | */ 470 | 471 | function classList(element) { 472 | return (' ' + (element.className || '') + ' ').replace(/\s+/gi, ' '); 473 | } 474 | 475 | /** 476 | * (Internal) Removes an element from the DOM. 477 | */ 478 | 479 | function removeElement(element) { 480 | element && element.parentNode && element.parentNode.removeChild(element); 481 | } 482 | 483 | return NProgress; 484 | }); 485 | -------------------------------------------------------------------------------- /src/utils/utils.js: -------------------------------------------------------------------------------- 1 | export const formatRes = (data, code = '0000') => { 2 | return { 3 | data, 4 | code, 5 | message: code === '0000' ? '请求成功' : '请求失败', 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | test('test 2 + 2', () => { 2 | expect(Math.floor(2.4)).toBe(2); 3 | }); 4 | 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "allowJs": true, 5 | "skipLibCheck": false, 6 | "esModuleInterop": false, 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | // "resolveJsonModule": true, 13 | "isolatedModules": false, 14 | "noEmit": true, 15 | "jsx": "preserve", 16 | "strictNullChecks": false, 17 | "baseUrl": "./", 18 | "paths": { 19 | "src/*": ["src/*"], 20 | "component/*": ["component/*"], 21 | "assets/*": ["assets/*"] 22 | }, 23 | "experimentalDecorators": true, 24 | "noImplicitAny": false 25 | }, 26 | "include": ["src"], 27 | "exclude": ["node_modules"] 28 | } 29 | --------------------------------------------------------------------------------