├── .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 |
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 |
28 | );
29 | return (
30 |
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 |
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
15 | {show ? children : null}
16 | >
17 | );
18 |
19 | type Props = { title: string };
20 | const ToggleableMenu: SFC = ({ title, children }) => (
21 | (
23 |
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 |
21 |
22 |
23 | 记住密码
24 |
25 | 忘记密码?
26 |
27 |
28 |
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 |
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 |
--------------------------------------------------------------------------------