├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── README.md
├── mock
└── 新建文本文档.txt
├── package.json
├── proxy.config.js
├── src
├── assets
│ ├── folder-96.png
│ ├── folder.png
│ ├── font
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ └── iconfont.woff
│ └── images
│ │ ├── css-64.png
│ │ ├── folder-64.png
│ │ ├── js-64.png
│ │ ├── psd-64.png
│ │ └── zip-64.png
├── index.css
├── index.html
├── index.js
├── models
│ ├── DiskModel
│ │ ├── DiskModel.js
│ │ └── index.js
│ ├── HomeModel
│ │ ├── HomeModel.js
│ │ └── index.js
│ └── index.js
├── pages
│ ├── DiskPage
│ │ ├── BlockBrowser
│ │ │ ├── File
│ │ │ │ ├── index.js
│ │ │ │ ├── jsx.js
│ │ │ │ └── styles.css
│ │ │ ├── FileMenu
│ │ │ │ ├── index.js
│ │ │ │ └── jsx.js
│ │ │ ├── FolderMenu
│ │ │ │ ├── index.js
│ │ │ │ └── jsx.js
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── CheckAll
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── CopyModal
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── Layout
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── Menu
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── MkdirModal
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── Mode
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── MoveModal
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── Path
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── RenameModal
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── Search
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── Total
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── index.js
│ │ ├── jsx.js
│ │ └── styles.css
│ ├── HomePage
│ │ ├── Layout
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── Nav
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── Side
│ │ │ ├── index.js
│ │ │ ├── jsx.js
│ │ │ └── styles.css
│ │ ├── index.js
│ │ ├── jsx.js
│ │ └── styles.css
│ └── index.js
├── router.js
├── services
│ └── DiskService
│ │ ├── DiskService.js
│ │ └── index.js
├── tests
│ └── models
│ │ └── example-test.js
└── utils
│ └── request.js
└── webpack.config.js
/.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 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | src/**/*-test.js
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": "eslint-config-airbnb",
4 | "rules": {
5 | "spaced-comment": [0],
6 | "no-unused-vars": [0],
7 | "no-empty": [0],
8 | "react/wrap-multilines": [0],
9 | "react/no-multi-comp": [0],
10 | "no-constant-condition": [0],
11 | "react/jsx-no-bind": [0],
12 | "react/prop-types": [0],
13 | "arrow-body-style": [0],
14 | "react/prefer-stateless-function": [0],
15 | "semi": [0],
16 | "global-require": [0],
17 | "no-shadow": [0],
18 | "no-useless-computed-key": [0],
19 | "no-underscore-dangle": [0]
20 | },
21 | "ecmaFeatures": {
22 | "experimentalObjectRestSpread": true
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # r2r-web
2 | 一个模仿百度网盘的前端实现
3 |
4 | 这是线上 DEMO
5 |
--------------------------------------------------------------------------------
/mock/新建文本文档.txt:
--------------------------------------------------------------------------------
1 | test
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "entry": {
4 | "index": "./src/index.js"
5 | },
6 | "dependencies": {
7 | "antd": "^2.4.3",
8 | "dva": "^1.1.0",
9 | "react": "^15.3.2",
10 | "react-contextmenu": "^2.0.0-alpha.2",
11 | "react-dom": "^15.3.2",
12 | "react-scrollbar": "^0.4.2"
13 | },
14 | "devDependencies": {
15 | "atool-build": "^0.9.0",
16 | "atool-test-mocha": "^0.1.5",
17 | "babel-plugin-dev-expression": "^0.2.1",
18 | "babel-plugin-dva-hmr": "^0.2.0",
19 | "babel-plugin-transform-runtime": "^6.9.0",
20 | "babel-runtime": "^6.9.2",
21 | "dora": "^0.4.3",
22 | "dora-plugin-proxy": "^0.8.4",
23 | "dora-plugin-webpack": "^0.8.1",
24 | "dora-plugin-webpack-hmr": "^0.2.1",
25 | "expect": "^1.20.2",
26 | "font-awesome": "^4.7.0",
27 | "redbox-react": "^1.3.2"
28 | },
29 | "scripts": {
30 | "start": "dora --plugins \"proxy?watchDirs=./mock,webpack,webpack-hmr\"",
31 | "build": "atool-build",
32 | "test": "atool-test-mocha ./src/**/*-test.js"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/proxy.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mock = {};
4 |
5 | require('fs').readdirSync(require('path').join(__dirname + '/mock'))
6 | .forEach(function (file) {
7 | Object.assign(mock, require('./mock/' + file));
8 | });
9 |
10 | module.exports = mock;
11 |
--------------------------------------------------------------------------------
/src/assets/folder-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/folder-96.png
--------------------------------------------------------------------------------
/src/assets/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/folder.png
--------------------------------------------------------------------------------
/src/assets/font/iconfont.css:
--------------------------------------------------------------------------------
1 |
2 | @font-face {font-family: "iconfont";
3 | src: url('iconfont.eot?t=1480059376323'); /* IE9*/
4 | src: url('iconfont.eot?t=1480059376323#iefix') format('embedded-opentype'), /* IE6-IE8 */
5 | url('iconfont.woff?t=1480059376323') format('woff'), /* chrome, firefox */
6 | url('iconfont.ttf?t=1480059376323') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
7 | url('iconfont.svg?t=1480059376323#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family:"iconfont" !important;
12 | font-size:16px;
13 | font-style:normal;
14 | -webkit-font-smoothing: antialiased;
15 | -webkit-text-stroke-width: 0.2px;
16 | -moz-osx-font-smoothing: grayscale;
17 | }
18 |
19 | .icon-duihao:before { content: "\e623"; }
20 |
21 | .icon-duihao1:before { content: "\e621"; }
22 |
23 | .icon-duihao2:before { content: "\e608"; }
24 |
25 |
--------------------------------------------------------------------------------
/src/assets/font/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/font/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/font/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
47 |
--------------------------------------------------------------------------------
/src/assets/font/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/font/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/font/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/font/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/images/css-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/images/css-64.png
--------------------------------------------------------------------------------
/src/assets/images/folder-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/images/folder-64.png
--------------------------------------------------------------------------------
/src/assets/images/js-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/images/js-64.png
--------------------------------------------------------------------------------
/src/assets/images/psd-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/images/psd-64.png
--------------------------------------------------------------------------------
/src/assets/images/zip-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuhjui-r2r/r2r-web/47610e4341d1cf41ee24434e7d42e5d4c23612db/src/assets/images/zip-64.png
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | :global(@font-face) {
4 | font-family: "iconfont";
5 | src: url('./assets/font/iconfont.eot'); /* IE9*/
6 | src: url('./assets/font/iconfont.eot') format('embedded-opentype'), /* IE6-IE8 */
7 | url('./assets/font/iconfont.woff') format('woff'), /* chrome, firefox */
8 | url('./assets/font/iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
9 | url('./assets/font/iconfont.svg') format('svg'); /* iOS 4.1- */
10 | }
11 |
12 | :global(.iconfont) {
13 | font-family:"iconfont" !important;
14 | font-size:16px;
15 | font-style:normal;
16 | -webkit-font-smoothing: antialiased;
17 | -webkit-text-stroke-width: 0.2px;
18 | -moz-osx-font-smoothing: grayscale;
19 | }
20 |
21 | :global(.icon-duihao:before){
22 | content: "\e623";
23 | }
24 |
25 |
26 | :global(.icon-duihao1:before){
27 | content: "\e621";
28 | }
29 |
30 |
31 | :global(.icon-duihao2:before){
32 | content: "\e608";
33 | }
34 |
35 |
36 |
37 | :global(*){
38 | margin: 0;
39 | padding: 0;
40 | }
41 |
42 | :global(html,body){
43 | width: 100%;
44 | height: 100%;
45 | }
46 |
47 | :global(#root){
48 | height: 100%;
49 | background: #EFF4F8;
50 | }
51 |
52 |
53 | /** react-contextmenu */
54 |
55 |
56 |
57 | :global(.react-contextmenu){
58 | min-width: 100px;
59 | padding: 2px 0;
60 | margin: 2px 0 0;
61 | font-size: 14px;
62 | color: #373a3c;
63 | text-align: left;
64 | background-color: #fff;
65 | background-clip: padding-box;
66 | border: 1px solid rgba(0,0,0,.15);
67 | border-radius: .25rem;
68 | outline: none;
69 | opacity: 0;
70 | }
71 |
72 |
73 | :global(.react-contextmenu.react-contextmenu--visible) {
74 | opacity: 1;
75 | pointer-events: auto;
76 | }
77 |
78 |
79 | :global(.react-contextmenu-item) {
80 | width: 100px;
81 | padding: 3px 20px;
82 | font-weight: 400;
83 | line-height: 1.5;
84 | color: #373a3c;
85 | text-align: inherit;
86 | white-space: nowrap;
87 | background: 0 0;
88 | border: 0;
89 | cursor: pointer;
90 | }
91 |
92 |
93 | :global(.react-contextmenu-item:hover) {
94 | color: #fff;
95 | background-color: #0275d8;
96 | border-color: #0275d8;
97 | text-decoration: none;
98 | }
99 |
100 |
101 |
102 |
103 | :global(.react-contextmenu-link) {
104 | display: inline-block;
105 | width: 100%;
106 | padding: 3px 20px;
107 | clear: both;
108 | font-weight: 400;
109 | line-height: 1.5;
110 | color: #373a3c;
111 | text-align: inherit;
112 | white-space: nowrap;
113 | background: 0 0;
114 | border: 0;
115 | }
116 |
117 | :global(.react-contextmenu-link.active,
118 | .react-contextmenu-link:hover) {
119 | color: #fff;
120 | background-color: #0275d8;
121 | border-color: #0275d8;
122 | text-decoration: none;
123 | }
124 | :global(.react-contextmenu-item.submenu > a) {
125 | padding-right: 27px;
126 | }
127 |
128 | :global(.react-contextmenu-item.submenu > a:after) {
129 | content: "▶";
130 | display: inline-block;
131 | position: absolute;
132 | right: 7px;
133 | }
134 |
135 | :global(.example-multiple-targets::after ){
136 | content: attr(data-count);
137 | display: block;
138 | }
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | R2R-WEB 分布式共享性网盘
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import './index.html';
2 | import './index.css';
3 | import 'antd/dist/antd.css'
4 | import 'font-awesome/css/font-awesome.css'
5 |
6 |
7 | import dva from 'dva';
8 |
9 | import { HomeModel,DiskModel } from "./models"
10 |
11 |
12 |
13 | // 1. Initialize
14 | const app = dva();
15 |
16 | // 2. Plugins
17 | //app.use({});
18 |
19 | // 3. Model
20 | app.model(HomeModel);
21 | app.model(DiskModel);
22 |
23 | // 4. Router
24 | app.router(require('./router'));
25 |
26 | // 5. Start
27 | app.start('#root');
28 |
29 |
--------------------------------------------------------------------------------
/src/models/DiskModel/DiskModel.js:
--------------------------------------------------------------------------------
1 | import DiskService from "../../services/DiskService"
2 | import { message } from "antd"
3 |
4 |
5 |
6 |
7 |
8 | const DiskModel = {
9 | namespace : "disk",
10 | state : {
11 | //路径,这是一个先进后出的栈结构,负责表达文件系统的层级结构
12 | path : [{id:0,name:"全部文件",type:"folder",parent_id:-1}],
13 | //目录树,负责表达目录的树结构
14 | tree : {id:0,name:"全部文件",list:[]},
15 | //文件列表负责保存基本的文件对象
16 | list : [],
17 | //该目录下的总元素数
18 | total : 0,
19 | // 对话框相关
20 | modal : {
21 | mkdir : {
22 | visible : false,
23 | load : false,
24 | text : "",
25 | },
26 | rename : {
27 | visible : false,
28 | load : false,
29 | text : "",
30 | source : "",
31 | target : "",
32 | },
33 | move : {
34 | visible : false,
35 | load : false,
36 | source_id : "",
37 | target_id : "",
38 | },
39 | copy : {
40 | visible : false,
41 | load : false,
42 | source_id : "",
43 | target_id : "",
44 | },
45 | },
46 | },
47 | reducers : {
48 | update(state,{ payload }){
49 | let data = {}
50 | if (payload.list){
51 | data.list=payload.list
52 | }
53 | if (payload.path){
54 | data.path=payload.path
55 | }
56 | if (payload.tree){
57 |
58 | data.tree=payload.tree
59 | }
60 | return { ...state,...data }
61 | },
62 | select( state ,{ payload : { file } }){
63 | state.list.forEach((el,i)=>{
64 | if (el.id == file.id){
65 | el.select = !el.select
66 | return false;
67 | }
68 | });
69 | return { ...state }
70 | },
71 | // 文件夹创建相关
72 | mkdir_modal_open(state){
73 | state.modal.mkdir.visible = true
74 | return { ...state }
75 | },
76 | mkdir_modal_change(state,{ payload : { text } }){
77 | state.modal.mkdir.text = text
78 | return { ...state }
79 | },
80 | mkdir_modal_load(state,action){
81 | state.modal.mkdir.load = action.payload
82 | return { ...state }
83 | },
84 | mkdir_modal_close(state){
85 | if (state.modal.mkdir.load){
86 | return state
87 | }
88 | state.modal.mkdir.visible = false
89 | state.modal.mkdir.text = ""
90 | return { ...state }
91 | },
92 | // 重命名相关
93 | rename_modal_open( state , { payload : { source } } ){
94 | state.modal.rename.visible = true
95 | state.modal.rename.source = source
96 | return { ...state }
97 | },
98 | rename_modal_change(state,{ payload : { text } }){
99 | state.modal.rename.text = text
100 | return { ...state }
101 | },
102 | rename_modal_load(state,action){
103 | state.modal.rename.load = action.payload;
104 | return { ...state }
105 | },
106 | rename_modal_close( state ){
107 | if (state.modal.rename.load){
108 | return state
109 | }
110 | state.modal.rename.visible = false
111 | state.modal.rename.text = ""
112 | state.modal.rename.source = ""
113 | return { ...state }
114 | },
115 | //文件移动相关
116 | move_modal_open( state,{ payload : { source_id } } ){
117 | state.modal.move.visible = true;
118 | state.modal.move.source_id = source_id+""
119 | state.modal.move.target_id = ""
120 | return { ...state }
121 | },
122 | move_modal_change(state,{ payload :{ target_id } }){
123 | state.modal.move.target_id = target_id;
124 | return { ...state }
125 | },
126 | move_modal_load(state,action){
127 | state.modal.move.load = action.payload;
128 | return { ...state }
129 | },
130 | move_modal_close(state){
131 | if (state.modal.move.load){
132 | return state
133 | }
134 | state.modal.move.visible = false;
135 | return { ...state }
136 | },
137 | //文件复制相关
138 | copy_modal_open( state,{ payload : { source_id } } ){
139 | state.modal.copy.visible = true;
140 | state.modal.copy.source_id = source_id+""
141 | state.modal.copy.target_id = ""
142 | return { ...state }
143 | },
144 | copy_modal_change(state,{ payload :{ target_id } }){
145 | state.modal.copy.target_id = target_id;
146 | return { ...state }
147 | },
148 | copy_modal_load(state,action){
149 | state.modal.copy.load = action.payload;
150 | return { ...state }
151 | },
152 | copy_modal_close(state){
153 | if (state.modal.copy.load){
154 | return state
155 | }
156 | state.modal.copy.visible = false;
157 | return { ...state }
158 | },
159 | },
160 | effects : {
161 | *fetch_list({ payload : { parent_id = 0 } },{call,put}){
162 | let { data } = yield call(DiskService.fetch_list, { parent_id });
163 | if (data.success) {
164 | yield put({type:"update",payload : data });
165 | }else{
166 | message.error(data.info);
167 | }
168 | },
169 | *fetch_tree( { payload }, { call,put } ){
170 | let { data } = yield call(DiskService.fetch_tree,{});
171 | if (data.success) {
172 | yield put({type:"update",payload : data });
173 | }else{
174 | message.error(data.info);
175 | }
176 | },
177 | *open_folder( { payload : { folder } },{ call,put } ){
178 | yield put({type : "fetch_list",payload:{ parent_id:folder.id } })
179 | },
180 | *mkdir({ payload : { parent_id,name } },{ call,put }){
181 | yield put({type : "mkdir_modal_load",payload:true});
182 | let { data } = yield call(DiskService.mkdir, { parent_id,name });
183 | yield put({type : "mkdir_modal_load",payload:false});
184 | yield put({type : "mkdir_modal_close"});
185 |
186 | if (data.success) {
187 | yield put({type:"fetch_list",payload:{ parent_id }})
188 | yield put({type:"fetch_tree",payload:{ }})
189 | }else{
190 | message.error(data.info);
191 | }
192 | },
193 | *rename( { payload : { parent_id,source,target } },{ call ,put } ){
194 | yield put({type : "rename_modal_load",payload:true});
195 | let { data } = yield call(DiskService.rename, { parent_id,source,target });
196 | yield put({type : "rename_modal_load",payload:false});
197 | yield put({type : "rename_modal_close"});
198 |
199 | if (data.success ){
200 | yield put({type : "fetch_list",payload:{parent_id}})
201 | yield put({type : "fetch_tree",payload:{}})
202 | }else{
203 | message.error(data.info)
204 | }
205 | },
206 | *remove( { payload :{ parent_id,id } },{ call,put } ){
207 | let { data } = yield call(DiskService.remove, { id });
208 | if (data.success ){
209 | yield put({type : "fetch_list",payload:{parent_id}})
210 | yield put({type : "fetch_tree",payload:{}})
211 | }else{
212 | message.error(data.info)
213 | }
214 | },
215 | *move( { payload : { parent_id,source_id, target_id} },{ call,put } ){
216 | yield put({type : "move_modal_load",payload:true});
217 | let { data } = yield call(DiskService.move, { source_id,target_id });
218 | yield put({type : "move_modal_load",payload:false});
219 | yield put({type : "move_modal_close"});
220 |
221 | if (data.success) {
222 | yield put({type:"fetch_list",payload:{ parent_id }})
223 | yield put({type:"fetch_tree",payload:{ }})
224 | }else{
225 | message.error(data.info);
226 | }
227 | },
228 | *copy( { payload : { parent_id,source_id, target_id} },{ call,put } ){
229 | yield put({type : "copy_modal_load",payload:true});
230 | let { data } = yield call(DiskService.copy, { source_id,target_id });
231 | yield put({type : "copy_modal_load",payload:false});
232 | yield put({type : "copy_modal_close"});
233 |
234 | if (data.success) {
235 | yield put({type:"fetch_list",payload:{ parent_id }})
236 | yield put({type:"fetch_tree",payload:{ }})
237 | }else{
238 | message.error(data.info);
239 | }
240 | },
241 | },
242 | subscriptions : {
243 | setup({ dispatch, history }) {
244 | return history.listen(({ pathname, query }) => {
245 | if (pathname === '/') {
246 | dispatch({ type: 'fetch_list', payload:{} });
247 | dispatch({ type: 'fetch_tree', payload:{} });
248 | }
249 | });
250 | },
251 | },
252 | };
253 |
254 |
255 | export default DiskModel
--------------------------------------------------------------------------------
/src/models/DiskModel/index.js:
--------------------------------------------------------------------------------
1 | import DiskModel from "./DiskModel.js"
2 |
3 | export default DiskModel
--------------------------------------------------------------------------------
/src/models/HomeModel/HomeModel.js:
--------------------------------------------------------------------------------
1 |
2 | const HomeModel = {
3 | namespace : "home",
4 | state : {},
5 | reducers : {},
6 |
7 | };
8 |
9 |
10 | export default HomeModel
--------------------------------------------------------------------------------
/src/models/HomeModel/index.js:
--------------------------------------------------------------------------------
1 | import HomeModel from "./HomeModel.js"
2 |
3 | export default HomeModel
--------------------------------------------------------------------------------
/src/models/index.js:
--------------------------------------------------------------------------------
1 | import HomeModel from "./HomeModel"
2 | import DiskModel from "./DiskModel"
3 |
4 | export { HomeModel,DiskModel }
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/File/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/File/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 |
4 |
5 | const File = ({ isSelect,type,name,onSelect }) => {
6 |
7 | let active = isSelect ? styles.active : '';
8 | let icon = styles['icon_'+type];
9 | if (!icon) icon=styles['icon_file'];
10 |
11 | return (
12 |
13 |
14 |
15 | {name}
16 |
17 |
18 |
19 | )
20 | }
21 |
22 |
23 | File.propTypes={};
24 |
25 |
26 | export default File;
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/File/styles.css:
--------------------------------------------------------------------------------
1 | .file {
2 | margin-top: 20px;
3 | width: 122px;
4 | height: 129px;
5 | display: inline-block;
6 | margin-left:10px;
7 | margin-right: 10px;
8 | text-align: center;
9 | cursor: pointer;
10 | position: relative;
11 | }
12 |
13 | .file:hover {
14 | background-color: #f1f5fa;
15 | border-radius: 5px;
16 | }
17 |
18 | .active {
19 | background-color: #f1f5fa;
20 | border: 1px solid #90c3fd;
21 | border-radius: 5px;
22 | }
23 |
24 | .checkbox {
25 | font-family:"iconfont";
26 | font-size:16px;
27 | color:#3b8cff;
28 | position: absolute;
29 | top: 5px;
30 | left: 5px;
31 | height: 21px;
32 | width: 21px;
33 | cursor: pointer;
34 | }
35 |
36 | .checkbox:before {
37 | content: "\e608";
38 | }
39 |
40 |
41 | .file .checkbox {
42 | display:none;
43 | }
44 |
45 | .file:hover .checkbox {
46 | display:block;
47 | opacity:0.5;
48 | }
49 |
50 | .file.active .checkbox {
51 | display:block;
52 | opacity:1;
53 | }
54 |
55 |
56 |
57 | .text {
58 | margin-top: 12px;
59 | font-family:"微软雅黑";
60 | font-size:12px;
61 | }
62 |
63 | .icon_file{
64 | width: 64px;
65 | height: 64px;
66 | background: url("../../../../assets/images/zip-64.png") no-repeat center ;
67 | display: inline-block;
68 | margin-top: 20px;
69 | }
70 |
71 | .icon_folder{
72 | width: 64px;
73 | height: 64px;
74 | background: url("../../../../assets/images/folder-64.png") no-repeat center ;
75 | display: inline-block;
76 | margin-top: 20px;
77 | }
78 |
79 | .icon_zip{
80 | width: 64px;
81 | height: 64px;
82 | background: url("../../../../assets/images/zip-64.png") no-repeat center ;
83 | display: inline-block;
84 | margin-top: 20px;
85 | }
86 |
87 | .icon_css{
88 | width: 64px;
89 | height: 64px;
90 | background: url("../../../../assets/images/css-64.png") no-repeat center ;
91 | display: inline-block;
92 | margin-top: 20px;
93 | }
94 |
95 | .icon_js{
96 | width: 64px;
97 | height: 64px;
98 | background: url("../../../../assets/images/js-64.png") no-repeat center ;
99 | display: inline-block;
100 | margin-top: 20px;
101 | }
102 |
103 |
104 | .icon_psd{
105 | width: 64px;
106 | height: 64px;
107 | background: url("../../../../assets/images/psd-64.png") no-repeat center ;
108 | display: inline-block;
109 | margin-top: 20px;
110 | }
111 |
112 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/FileMenu/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/FileMenu/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ContextMenu, MenuItem, ContextMenuTrigger,SubMenu } from "react-contextmenu";
3 |
4 |
5 | const FileMenu = ({ id,onEvent })=>{
6 |
7 | const onHandle = (e,data,target) => {
8 | onEvent(data);
9 | }
10 |
11 | return (
12 |
13 |
16 |
19 |
22 |
25 |
28 |
31 |
32 | );
33 | }
34 |
35 | FileMenu.propTypes={};
36 |
37 |
38 | export default FileMenu;
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/FolderMenu/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/FolderMenu/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ContextMenu, MenuItem, ContextMenuTrigger,SubMenu } from "react-contextmenu";
3 |
4 |
5 | const FolderMenu = ({ id,onEvent })=>{
6 |
7 | const onHandle = (e,data,target) => {
8 | onEvent(data);
9 | }
10 |
11 | return (
12 |
13 |
16 |
19 |
22 |
25 |
28 |
31 |
32 | );
33 | }
34 |
35 | FolderMenu.propTypes={};
36 |
37 |
38 | export default FolderMenu;
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { ContextMenuTrigger} from "react-contextmenu";
4 |
5 | import File from "./File"
6 | import FileMenu from './FileMenu';
7 | import FolderMenu from "./FolderMenu"
8 |
9 |
10 | const FileMenuID = "file_menu_id"
11 | const FolderMenuID = "folder_menu_id"
12 |
13 |
14 | const collect = (props) => {
15 | return { fileID: props.fileID };
16 | }
17 |
18 | const CreateFile = ({fileID,name,type,select,onSelect})=>{
19 | let onHandle = () =>{
20 | onSelect(fileID)
21 | }
22 | return (
23 |
24 |
25 |
26 |
27 |
28 | )
29 | }
30 |
31 | const CreateFolder = ({ fileID,name,select,onSelect }) => {
32 | let onHandle = () =>{
33 | onSelect(fileID)
34 | }
35 |
36 | return (
37 |
38 |
39 |
40 |
41 |
42 | );
43 | }
44 |
45 |
46 | const BlockBrowser = ({ list,bus }) => {
47 |
48 | let onSelect = (fileID) => {
49 | let file = list[fileID]
50 | bus.publish("SELECT", { file });
51 | }
52 |
53 | let onMenu = ({ type,fileID }) => {
54 | if ( type == "rename" ){
55 | let file = list[fileID];
56 | return bus.publish("RENAME_MODAL_OPEN",{file});
57 | }
58 | if ( type == "open_folder" ){
59 | let folder = list[fileID]
60 | return bus.publish("OPEN_FOLDER",{ folder });
61 | }
62 | if ( type == "remove" ){
63 | let file = list[fileID]
64 | return bus.publish("REMOVE_FILE",{ file });
65 | }
66 | if ( type == "move" ){
67 | let file = list[fileID]
68 | return bus.publish("MOVE_MODAL_OPEN",{ file });
69 | }
70 | if ( type == "copy" ){
71 | let file = list[fileID]
72 | return bus.publish("COPY_MODAL_OPEN",{ file });
73 | }
74 | }
75 |
76 |
77 | let FileList = list.map(function(el,i){
78 | let fileID = i;
79 | if (el.type == "folder") {
80 | return CreateFolder({ ...el,fileID,onSelect})
81 | }else{
82 | return CreateFile({ ...el,fileID,onSelect });
83 | }
84 | })
85 |
86 | return (
87 |
88 | {[ FileList ]}
89 |
90 |
91 |
92 | )
93 | }
94 |
95 |
96 | BlockBrowser.propTypes={};
97 |
98 |
99 | export default BlockBrowser;
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/BlockBrowser/styles.css:
--------------------------------------------------------------------------------
1 | .block_browser{
2 | }
3 |
4 | .file{
5 | width: 122px;
6 | margin-left:4px;
7 | margin-right:4px;
8 | display:inline-block;
9 | }
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/CheckAll/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/CheckAll/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { Checkbox } from 'antd';
4 |
5 | const CheckAll = (props) => {
6 | return (
7 |
8 |
9 | 全选
10 |
11 |
12 | )
13 | }
14 |
15 |
16 | CheckAll.propTypes={};
17 |
18 |
19 | export default CheckAll;
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/CheckAll/styles.css:
--------------------------------------------------------------------------------
1 | .check_all{
2 | padding-top:5px;
3 | padding-left:15px;
4 | }
--------------------------------------------------------------------------------
/src/pages/DiskPage/CopyModal/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/CopyModal/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { message,Modal, Tree } from 'antd';
4 |
5 | const Node = Tree.TreeNode;
6 |
7 |
8 | // 映射到树组件
9 | const mapToTree = (node) => {
10 | if (node.list.length > 0){
11 | let comps = [];
12 | node.list.forEach((el)=>{
13 | let comp = mapToTree(el)
14 | comps.push(comp)
15 | });
16 | return (
17 |
18 | { comps }
19 |
20 | );
21 | }else{
22 | return (
23 |
24 | );
25 | }
26 | }
27 |
28 |
29 | const CopyModal = ({ tree,visible,load,source_id,target_id,bus })=>{
30 |
31 | const onSelect = ( keys ) =>{
32 | let key = keys[0]
33 | if(key){
34 | bus.publish("COPY_MODAL_CHANGE",{ key })
35 | }else{
36 | bus.publish("COPY_MODAL_CHANGE",{ key:"" })
37 | }
38 | }
39 |
40 | let onOk = ()=>{
41 | if (target_id == ""){
42 | message.error("请选择一个目录")
43 | return;
44 | }
45 | bus.publish("COPY_MODAL_CONFIRM",{source_id,target_id})
46 | }
47 |
48 | const onCancel = ()=>{
49 | bus.publish("COPY_MODAL_CLOSE",{});
50 | }
51 |
52 |
53 | let comp = mapToTree(tree);
54 |
55 | return (
56 |
57 |
65 |
66 |
70 | { comp }
71 |
72 |
73 |
74 |
75 | )
76 | }
77 |
78 | CopyModal.propTypes={};
79 |
80 |
81 | export default CopyModal;
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/CopyModal/styles.css:
--------------------------------------------------------------------------------
1 | .panel{
2 | width:100%;
3 | height: 200px;
4 | }
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Layout/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/Layout/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import Scroll from 'react-scrollbar';
4 |
5 |
6 | const Layout = ({ Menu,Search,Mode,Path,Total,CheckAll,Browser })=>{
7 | return (
8 |
9 |
10 |
11 | { Menu }
12 |
13 |
14 | { Mode }
15 |
16 |
17 | { Search }
18 |
19 |
20 |
21 |
22 | { Path }
23 |
24 |
25 | { Total }
26 |
27 |
28 |
29 |
30 | { CheckAll }
31 |
32 |
33 |
34 |
35 |
36 | { Browser }
37 |
38 |
39 |
40 |
41 | )
42 | }
43 |
44 | Layout.propTypes={};
45 |
46 |
47 | export default Layout;
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Layout/styles.css:
--------------------------------------------------------------------------------
1 | .root{
2 | width:100%;
3 | height: 100%;
4 | background: #fff;
5 | border-radius: 10px;
6 | }
7 |
8 |
9 | .layer1{
10 | height:50px;
11 | }
12 |
13 | .layer2{
14 | height:20px;
15 | }
16 |
17 | .layer3{
18 | height:29px;
19 | }
20 |
21 | .layer4{
22 | border-top: 1px solid #d8dfea;
23 | width:100%;
24 | height: calc(100% - 100px );
25 | }
26 |
27 |
28 | .menu{
29 | float:left;
30 | }
31 |
32 | .search{
33 | float:right;
34 | }
35 |
36 | .mode{
37 | float:right;
38 | }
39 |
40 | .path{
41 | float:left;
42 | }
43 |
44 | .total{
45 | float:right;
46 | }
47 |
48 | .check_all{
49 |
50 | }
51 |
52 | .browser{
53 | width:100%;
54 | height:100%;
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Menu/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/Menu/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { Button } from 'antd';
4 |
5 |
6 | const Menu = ({ bus })=>{
7 |
8 | let onMkdir = ()=>{
9 | bus.publish("MKDIR_MODAL_OPEN")
10 | }
11 |
12 |
13 | return (
14 |
15 |
16 |
22 |
23 |
24 |
30 |
31 |
32 |
38 |
39 |
40 |
46 |
47 |
48 | );
49 | };
50 |
51 |
52 | Menu.propTypes={}
53 |
54 | export default Menu;
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Menu/styles.css:
--------------------------------------------------------------------------------
1 | .menu{
2 | padding-top: 10px;
3 | padding-left: 15px;
4 | }
5 |
6 |
7 | .item{
8 | display:inline-block;
9 | margin-right:10px;
10 | }
11 |
12 | .text{
13 | display:inline;
14 | margin-left:3px
15 | }
16 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/MkdirModal/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/MkdirModal/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { message,Modal,Input } from 'antd';
4 |
5 |
6 |
7 | const MkdirModal = ({ visible,load,text,bus })=>{
8 | let onChange = (e)=>{
9 | let val = e.target.value;
10 | bus.publish("MKDIR_MODAL_CHANGE",{text:val})
11 | }
12 |
13 | let onOk = ()=>{
14 | if (text == ""){
15 | message.error("文件名不能为空")
16 | return;
17 | }
18 | bus.publish("MKDIR_MODAL_CONFIRM",{name:text})
19 | }
20 |
21 | let onCancel = ()=>{
22 | bus.publish("MKDIR_MODAL_CLOSE")
23 | }
24 |
25 | return (
26 |
27 |
35 |
40 |
41 |
42 | )
43 | }
44 |
45 | MkdirModal.propTypes={};
46 |
47 |
48 | export default MkdirModal;
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/MkdirModal/styles.css:
--------------------------------------------------------------------------------
1 | .root{
2 | width:100%;
3 | height: 100%;
4 | background: #fff;
5 | border-radius: 10px;
6 | }
7 |
8 |
9 | .layer1{
10 | height:50px;
11 | }
12 |
13 | .layer2{
14 | height:20px;
15 | }
16 |
17 | .layer3{
18 | height:29px;
19 | }
20 |
21 | .layer4{
22 | border-top: 1px solid #d8dfea;
23 | width:100%;
24 | height: calc(100% - 100px );
25 | }
26 |
27 |
28 | .menu{
29 | float:left;
30 | }
31 |
32 | .search{
33 | float:right;
34 | }
35 |
36 | .mode{
37 | float:right;
38 | }
39 |
40 | .path{
41 | float:left;
42 | }
43 |
44 | .total{
45 | float:right;
46 | }
47 |
48 | .check_all{
49 |
50 | }
51 |
52 | .browser{
53 | width:100%;
54 | height:100%;
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Mode/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/Mode/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { Radio } from 'antd';
4 |
5 |
6 | const Mode = (props) => {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | )
19 | }
20 |
21 |
22 |
23 | Mode.propTypes={};
24 |
25 |
26 | export default Mode;
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Mode/styles.css:
--------------------------------------------------------------------------------
1 | .mode{
2 | padding-right: 15px;
3 | padding-top: 15px;
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/MoveModal/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/MoveModal/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { message,Modal, Tree } from 'antd';
4 |
5 | const Node = Tree.TreeNode;
6 |
7 |
8 | // 映射到树组件
9 | const mapToTree = (node) => {
10 | if (node.list.length > 0){
11 | let comps = [];
12 | node.list.forEach((el)=>{
13 | let comp = mapToTree(el)
14 | comps.push(comp)
15 | });
16 | return (
17 |
18 | { comps }
19 |
20 | );
21 | }else{
22 | return (
23 |
24 | );
25 | }
26 | }
27 |
28 |
29 | const MoveModal = ({ tree,visible,load,source_id,target_id,bus })=>{
30 |
31 | const onSelect = ( keys ) =>{
32 | let key = keys[0]
33 | if(key){
34 | bus.publish("MOVE_MODAL_CHANGE",{ key })
35 | }else{
36 | bus.publish("MOVE_MODAL_CHANGE",{ key:"" })
37 | }
38 | }
39 |
40 | let onOk = ()=>{
41 | if (target_id == ""){
42 | message.error("请选择一个目录")
43 | return;
44 | }
45 | bus.publish("MOVE_MODAL_CONFIRM",{source_id,target_id})
46 | }
47 |
48 | const onCancel = ()=>{
49 | bus.publish("MOVE_MODAL_CLOSE",{});
50 | }
51 |
52 |
53 | let comp = mapToTree(tree);
54 |
55 | return (
56 |
57 |
65 |
66 |
70 | { comp }
71 |
72 |
73 |
74 |
75 | )
76 | }
77 |
78 | MoveModal.propTypes={};
79 |
80 |
81 | export default MoveModal;
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/MoveModal/styles.css:
--------------------------------------------------------------------------------
1 | .panel{
2 | width:100%;
3 | height: 200px;
4 | }
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Path/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/Path/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { Breadcrumb } from 'antd';
4 |
5 |
6 |
7 | const makeLast = ( folder ) =>{
8 | return (
9 |
10 | { folder.name }
11 |
12 | );
13 | }
14 |
15 |
16 | const makeChain = (data,onEvent)=>{
17 | let array = []
18 | if (data.length == 0){
19 | return []
20 | }
21 | let last = makeLast(data.pop());
22 | data.forEach((folder,i)=>{
23 | const onClick = ()=>{
24 | onEvent(folder)
25 | }
26 | let comp = (
27 |
28 | { folder.name }
29 |
30 | );
31 | array.push(comp)
32 | });
33 | array.push(last)
34 |
35 | return array
36 | }
37 |
38 |
39 | const Path = ({ path,bus }) => {
40 | let data = [ ...path ]
41 | if( data.length == 1 ){
42 | return (
43 |
46 | );
47 | }
48 |
49 | var root = data.shift()
50 | var prev = data[data.length-2];
51 |
52 |
53 | const onRoot = () => {
54 | bus.publish("OPEN_FOLDER",{ folder:root })
55 | }
56 |
57 | const onPrev = () => {
58 | if (prev){
59 | bus.publish("OPEN_FOLDER",{ folder:prev })
60 | }else{
61 | bus.publish("OPEN_FOLDER",{ folder:root })
62 | }
63 | }
64 |
65 | const onEvent = (folder) => {
66 | bus.publish("OPEN_FOLDER",{ folder })
67 | }
68 |
69 | var chain = makeChain(data,onEvent)
70 |
71 |
72 | return (
73 |
74 |
88 |
89 |
90 | {[ chain ]}
91 |
92 |
93 |
94 | );
95 | }
96 |
97 |
98 | Path.propTypes={};
99 |
100 |
101 | export default Path;
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Path/styles.css:
--------------------------------------------------------------------------------
1 | .path{
2 | padding-left: 15px;
3 | }
4 |
5 |
6 | .anchor{
7 | display:inline-block;
8 | }
9 |
10 | .anchor > a {
11 | display:inline-block;
12 | }
13 |
14 | .chain{
15 | display:inline-block;
16 | }
17 |
18 | .delim{
19 | padding-left:5px;
20 | padding-right:5px;
21 | display:inline-block;
22 | }
--------------------------------------------------------------------------------
/src/pages/DiskPage/RenameModal/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/RenameModal/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { message,Modal,Input } from 'antd';
4 |
5 |
6 |
7 | const RenameModal = ({ visible,load,text,bus })=>{
8 | let onChange = (e)=>{
9 | let val = e.target.value;
10 | bus.publish("RENAME_MODAL_CHANGE",{text:val})
11 | }
12 |
13 | let onOk = ()=>{
14 | if (text == ""){
15 | message.error("文件名不能为空")
16 | return;
17 | }
18 | bus.publish("RENAME_MODAL_CONFIRM",{name:text})
19 | }
20 |
21 | let onCancel = ()=>{
22 | bus.publish("RENAME_MODAL_CLOSE")
23 | }
24 |
25 | return (
26 |
27 |
35 |
40 |
41 |
42 | )
43 | }
44 |
45 | RenameModal.propTypes={};
46 |
47 |
48 | export default RenameModal;
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/RenameModal/styles.css:
--------------------------------------------------------------------------------
1 | .root{
2 | width:100%;
3 | height: 100%;
4 | background: #fff;
5 | border-radius: 10px;
6 | }
7 |
8 |
9 | .layer1{
10 | height:50px;
11 | }
12 |
13 | .layer2{
14 | height:20px;
15 | }
16 |
17 | .layer3{
18 | height:29px;
19 | }
20 |
21 | .layer4{
22 | border-top: 1px solid #d8dfea;
23 | width:100%;
24 | height: calc(100% - 100px );
25 | }
26 |
27 |
28 | .menu{
29 | float:left;
30 | }
31 |
32 | .search{
33 | float:right;
34 | }
35 |
36 | .mode{
37 | float:right;
38 | }
39 |
40 | .path{
41 | float:left;
42 | }
43 |
44 | .total{
45 | float:right;
46 | }
47 |
48 | .check_all{
49 |
50 | }
51 |
52 | .browser{
53 | width:100%;
54 | height:100%;
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Search/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/Search/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 | import { Input } from 'antd';
4 |
5 |
6 | const Search = (props)=>{
7 | return (
8 |
9 |
12 |
13 | )
14 | }
15 |
16 |
17 | Search.propTypes={};
18 |
19 | export default Search;
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Search/styles.css:
--------------------------------------------------------------------------------
1 | .search{
2 | width:200px;
3 | padding-right: 15px;
4 | padding-top: 15px;
5 | }
--------------------------------------------------------------------------------
/src/pages/DiskPage/Total/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/Total/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 |
4 |
5 | const Total = (props)=>{
6 | return (
7 |
10 | )
11 | }
12 |
13 |
14 | Total.propTypes={};
15 |
16 | export default Total;
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/Total/styles.css:
--------------------------------------------------------------------------------
1 | .total{
2 | padding-right:15px;
3 | }
--------------------------------------------------------------------------------
/src/pages/DiskPage/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/DiskPage/jsx.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import EventBus from "@nsisodiya/eventbus";
3 |
4 | import styles from "./styles.css";
5 | import { connect } from 'dva';
6 | import { message } from "antd";
7 |
8 |
9 | import Layout from "./Layout"
10 | import Menu from "./Menu"
11 | import Search from "./Search"
12 | import Mode from "./Mode"
13 | import Path from "./Path"
14 | import Total from "./Total"
15 | import CheckAll from "./CheckAll"
16 | import BlockBrowser from "./BlockBrowser"
17 | import MkdirModal from "./MkdirModal"
18 | import RenameModal from "./RenameModal"
19 | import MoveModal from "./MoveModal"
20 | import CopyModal from "./CopyModal"
21 |
22 |
23 | function DiskPage({ disk ,dispatch }){
24 |
25 | let bus = new EventBus()
26 | bus.subscribe("SELECT",function( { file } ){
27 | dispatch({
28 | type : "disk/select",
29 | payload:{ file }
30 | });
31 | });
32 |
33 | //目录相关
34 | bus.subscribe("OPEN_FOLDER",function({ folder }){
35 | dispatch({
36 | type : "disk/open_folder",
37 | payload : { folder }
38 | });
39 | });
40 |
41 | //文件夹创建相关
42 | bus.subscribe("MKDIR_MODAL_OPEN",function(){
43 | dispatch({
44 | type:"disk/mkdir_modal_open"
45 | });
46 | });
47 | bus.subscribe("MKDIR_MODAL_CHANGE",function({ text }){
48 | dispatch({
49 | type : "disk/mkdir_modal_change",
50 | payload:{text},
51 | });
52 | });
53 | bus.subscribe("MKDIR_MODAL_CONFIRM",function({ name }){
54 | let parent_id = disk.path[disk.path.length-1].id
55 | dispatch({
56 | type : "disk/mkdir",
57 | payload : { parent_id,name }
58 | });
59 | });
60 | bus.subscribe("MKDIR_MODAL_CLOSE",function(){
61 | dispatch({
62 | type : "disk/mkdir_modal_close",
63 | });
64 | });
65 |
66 | //重命名相关
67 | bus.subscribe("RENAME_MODAL_OPEN",function({ file }){
68 | dispatch({
69 | type:"disk/rename_modal_open",
70 | payload : { source:file.name }
71 | });
72 | });
73 | bus.subscribe("RENAME_MODAL_CHANGE",function({ text }){
74 | dispatch({
75 | type : "disk/rename_modal_change",
76 | payload : { text },
77 | });
78 | });
79 | bus.subscribe("RENAME_MODAL_CONFIRM",function( { name } ){
80 | let parent_id = disk.path[disk.path.length-1].id
81 | dispatch({
82 | type : "disk/rename",
83 | payload : {
84 | parent_id : parent_id,
85 | source : disk.modal.rename.source,
86 | target : name
87 | }
88 | });
89 | });
90 | bus.subscribe("RENAME_MODAL_CLOSE",function(){
91 | dispatch({
92 | type : "disk/rename_modal_close",
93 | });
94 | });
95 |
96 | //删除相关
97 | bus.subscribe("REMOVE_FILE",function({ file }){
98 | let parent_id = disk.path[disk.path.length-1].id
99 | dispatch({
100 | type : "disk/remove",
101 | payload:{ parent_id:parent_id,id:file.id }
102 | });
103 | });
104 |
105 | //移动文件相关
106 | bus.subscribe("MOVE_MODAL_OPEN",function({ file }){
107 | dispatch({
108 | type : "disk/move_modal_open",
109 | payload : { source_id :file.id+"" },
110 | });
111 | });
112 | bus.subscribe("MOVE_MODAL_CHANGE",function({ key }){
113 | dispatch({
114 | type : "disk/move_modal_change",
115 | payload : { target_id:key },
116 | });
117 | });
118 | bus.subscribe("MOVE_MODAL_CONFIRM",function( { source_id,target_id } ){
119 | let parent_id = disk.path[disk.path.length-1].id
120 | dispatch({
121 | type : "disk/move",
122 | payload : {
123 | parent_id : parent_id,
124 | source_id : source_id,
125 | target_id : target_id,
126 | }
127 | });
128 | });
129 | bus.subscribe("MOVE_MODAL_CLOSE",function(){
130 | dispatch({
131 | type : "disk/move_modal_close",
132 | payload : {},
133 | });
134 | });
135 |
136 | //复制文件相关
137 | bus.subscribe("COPY_MODAL_OPEN",function({ file }){
138 | dispatch({
139 | type : "disk/copy_modal_open",
140 | payload : { source_id :file.id+"" },
141 | });
142 | });
143 | bus.subscribe("COPY_MODAL_CHANGE",function({ key }){
144 | dispatch({
145 | type : "disk/copy_modal_change",
146 | payload : { target_id:key },
147 | });
148 | });
149 | bus.subscribe("COPY_MODAL_CONFIRM",function( { source_id,target_id } ){
150 | let parent_id = disk.path[disk.path.length-1].id
151 | dispatch({
152 | type : "disk/copy",
153 | payload : {
154 | parent_id : parent_id,
155 | source_id : source_id,
156 | target_id : target_id,
157 | }
158 | });
159 | });
160 | bus.subscribe("COPY_MODAL_CLOSE",function(){
161 | dispatch({
162 | type : "disk/copy_modal_close",
163 | payload : {},
164 | });
165 | });
166 |
167 |
168 |
169 | return (
170 |
171 |
)}
173 | Search = {(
)}
174 | Mode = {(
)}
175 | Path = {(
)}
176 | Total = {(
)}
177 | CheckAll = {(
)}
178 | Browser = {(
)}
179 | />
180 |
186 |
192 |
200 |
208 |
209 | );
210 | };
211 |
212 | DiskPage.propTypes = {
213 | };
214 |
215 | function mapStateToProps({disk}) {
216 | return {disk};
217 | }
218 |
219 | export default connect(mapStateToProps)(DiskPage);
220 |
221 |
222 |
223 |
--------------------------------------------------------------------------------
/src/pages/DiskPage/styles.css:
--------------------------------------------------------------------------------
1 | .disk{
2 | width:100%;
3 | height: 100%;
4 | }
5 |
--------------------------------------------------------------------------------
/src/pages/HomePage/Layout/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/HomePage/Layout/jsx.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import { Row , Col } from 'antd'
3 | import styles from './styles.css';
4 |
5 |
6 |
7 | function Layout({ Nav , Side , Render }){
8 | return (
9 |
10 |
11 |
12 |
13 | R2R-WEB
14 |
15 |
16 |
17 | { Nav }
18 |
19 |
20 |
21 |
22 | { Side }
23 |
24 |
25 |
26 | { Render }
27 |
28 |
29 |
30 |
31 | );
32 | };
33 |
34 | Layout.propTypes = {
35 | };
36 |
37 |
38 | export default Layout
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/pages/HomePage/Layout/styles.css:
--------------------------------------------------------------------------------
1 | .all {
2 | width: 100%;
3 | height: 100%;
4 | }
5 |
6 | .top {
7 | height: 62px;
8 | }
9 |
10 | .logo{
11 | width: 100%;
12 | height: 100%;
13 | display: block;
14 | font-size: 24px;
15 | font-weight: bold;
16 | color: #4E97FF;
17 | text-align: center;
18 | margin-top: 15px;
19 | }
20 |
21 | .main {
22 | height: calc(100% - 62px );
23 | }
24 |
25 | .side {
26 | height: 100%;
27 | }
28 |
29 | .content{
30 | height: 100%;
31 | }
32 |
33 |
34 | .render {
35 | width: calc(100% - 10px);
36 | height: 100%;
37 | background: #fff;
38 | border: 1px solid #d8dfea;
39 | border-radius: 10px;
40 | }
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/pages/HomePage/Nav/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/HomePage/Nav/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 |
4 |
5 | const Nav = (props)=>{
6 | return (
7 |
8 | - 网盘
9 | - 发现资源
10 | - 我的共享
11 | - 朋友
12 |
13 | );
14 | }
15 |
16 | Nav.propTypes={}
17 |
18 | export default Nav;
19 |
--------------------------------------------------------------------------------
/src/pages/HomePage/Nav/styles.css:
--------------------------------------------------------------------------------
1 | .nav{
2 | height: 62px;
3 | width: 100%;
4 | font-size: 16px;
5 |
6 | font-family: "微软雅黑";
7 | }
8 |
9 | .nav > li{
10 | display: inline-block;
11 | height: 100%;
12 | width: 150px;
13 | line-height: 62px;
14 | text-align: center;
15 | cursor: pointer;
16 | }
17 |
18 | .nav > li:hover {
19 | color: #2db7f5;
20 | }
21 |
--------------------------------------------------------------------------------
/src/pages/HomePage/Side/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/HomePage/Side/jsx.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styles from './styles.css';
3 |
4 | const Side = (props) => {
5 | return (
6 |
7 | -
8 |
9 |
10 | 全部文件
11 |
12 |
13 | -
14 |
15 |
16 | 图片
17 |
18 |
19 | -
20 |
21 |
22 | 文档
23 |
24 |
25 | -
26 |
27 |
28 | 视频
29 |
30 |
31 | -
32 |
33 |
34 | 种子
35 |
36 |
37 | -
38 |
39 |
40 | 音乐
41 |
42 |
43 | -
44 |
45 |
46 | 其他
47 |
48 |
49 |
50 | );
51 | }
52 |
53 | Side.propTypes={};
54 |
55 | export default Side;
56 |
--------------------------------------------------------------------------------
/src/pages/HomePage/Side/styles.css:
--------------------------------------------------------------------------------
1 | .side {
2 | width: 100%;
3 | font-size: 16px;
4 | padding-top: 20px;
5 | }
6 |
7 | .side > li {
8 | height: 50px;
9 | line-height: 50px;
10 | width: 100%;
11 | font-size: 0px;
12 | }
13 |
14 | .side > li:hover {
15 | background: #E4E9EC;
16 | color: #2db7f5;
17 | }
18 |
19 | .active {
20 | background: #E4E9EC;
21 | color: #2db7f5;
22 | }
23 |
24 | .left{
25 | display: inline-block;
26 | font-size: 16px;
27 | width: 40px;
28 | }
29 |
30 | .right{
31 | display: inline-block;
32 | font-size: 16px;
33 | }
34 |
--------------------------------------------------------------------------------
/src/pages/HomePage/index.js:
--------------------------------------------------------------------------------
1 | import Component from "./jsx.js"
2 |
3 | export default Component
--------------------------------------------------------------------------------
/src/pages/HomePage/jsx.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import { Row , Col , Menu , Button } from 'antd'
3 | import Layout from "./Layout"
4 | import Nav from './Nav';
5 | import Side from './Side';
6 |
7 |
8 | import { connect } from 'dva';
9 |
10 | import styles from './styles.css';
11 |
12 |
13 | /*
14 | import { Link } from 'dva/router';
15 | import FileManager from '../../components/FileManager'
16 |
17 | import Side from '../../components/Side';
18 | import { routerRedux } from 'dva/router';
19 | */
20 |
21 |
22 |
23 |
24 |
25 | const SubMenu = Menu.SubMenu;
26 |
27 | const MenuItem = Menu.Item;
28 |
29 |
30 |
31 | function HomePage(props){
32 | return (
33 | )}
35 | Side = {()}
36 | Render = {(props.children)}
37 | />
38 | );
39 | };
40 |
41 | HomePage.propTypes = {
42 | };
43 |
44 | function mapStateToProps({home}) {
45 | return {home};
46 | }
47 |
48 | export default connect(mapStateToProps)(HomePage);
49 |
50 |
51 |
52 |
53 |
54 | /*
55 |
56 | function IndexPage({main,dispatch}) {
57 |
58 | const {filelist} = main
59 |
60 |
61 | setTimeout(()=>{
62 | dispatch({
63 | type:'main/fetch',
64 | payload:{}
65 | });
66 | },500);
67 |
68 |
69 |
70 | const onMkdir = (path) => {
71 |
72 | console.log("ip mkdir success");
73 | }
74 |
75 | const onChange = (event)=>{
76 | dispatch({
77 | type:'main/select_file',
78 | payload:event.data,
79 | });
80 | }
81 |
82 | const onOperation = (event)=>{
83 | if (event.type == 'reload') {
84 | dispatch({
85 | type:'main/fetch',
86 | payload:{}
87 | });
88 | }
89 | }
90 |
91 | return (
92 |
93 |
94 |
95 |
96 | R2R-WEB
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | );
113 | }
114 |
115 |
116 | IndexPage.propTypes = {
117 | };
118 |
119 |
120 | function mapStateToProps({main}) {
121 | return {main};
122 | }
123 |
124 |
125 |
126 | export default connect(mapStateToProps)(IndexPage);
127 | */
--------------------------------------------------------------------------------
/src/pages/HomePage/styles.css:
--------------------------------------------------------------------------------
1 |
2 | .test{
3 | width: 100%;
4 | height: 100%;
5 | }
6 |
7 | .test2 {
8 | width: calc(100% - 10px);
9 | height: 100%;
10 | background: #fff;
11 | border: 1px solid #d8dfea;
12 | border-radius: 10px;
13 | }
14 |
15 |
16 | .test4 {
17 | width: 150px;
18 | position: relative;
19 | top: 50px;
20 | left: 50px;
21 | font-size: 12px;
22 | }
23 |
24 |
25 |
26 | .logo{
27 | width: 100%;
28 | height: 100%;
29 | display: block;
30 | font-size: 24px;
31 | font-weight: bold;
32 | color: #4E97FF;
33 | text-align: center;
34 | margin-top: 15px;
35 | }
36 |
37 |
38 | .test3 {
39 | width: 100%;
40 | height: 100%;
41 | }
42 |
43 |
44 | .all {
45 | width: 100%;
46 | height: 100%;
47 | }
48 |
49 | .top {
50 | height: 62px;
51 | }
52 |
53 | .main {
54 | height: calc(100% - 62px );
55 | }
56 |
57 | .side {
58 | height: 100%;
59 | }
60 |
61 | .content{
62 | height: 100%;
63 | }
64 |
65 |
66 |
67 | .normal {
68 | font-family: Georgia, sans-serif;
69 | text-align: center;
70 | }
71 |
72 | .title {
73 | font-size: 2.5rem;
74 | font-weight: normal;
75 | letter-spacing: -1px;
76 | }
77 |
78 | .welcome {
79 | height: 328px;
80 |
81 | background-size: 388px 328px;
82 | }
83 |
84 | .list {
85 | font-size: 1.2em;
86 | margin-top: 1.8em;
87 | list-style: none;
88 | line-height: 1.5em;
89 | }
90 |
91 | .list code {
92 | background: #f7f7f7;
93 | }
94 |
--------------------------------------------------------------------------------
/src/pages/index.js:
--------------------------------------------------------------------------------
1 | import HomePage from "./HomePage"
2 | import DiskPage from "./DiskPage"
3 |
4 | export { HomePage,DiskPage }
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import { Router, Route, IndexRoute, Link } from 'dva/router';
3 |
4 |
5 | import { HomePage,DiskPage } from './pages';
6 |
7 |
8 | export default function({ history }) {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/src/services/DiskService/DiskService.js:
--------------------------------------------------------------------------------
1 | import request from '../../utils/request';
2 |
3 | const PAGE_SIZE = 10
4 |
5 | const URL = ""
6 |
7 | export function fetch_list({ parent_id=0 }){
8 | return request(URL+`/api/disk/fetch_list?parent_id=${parent_id}`);
9 | }
10 |
11 | export function fetch_tree(){
12 | return request(URL+"/api/disk/fetch_tree?parent_id=0")
13 | }
14 |
15 |
16 | export function mkdir({ parent_id = 0 ,name }){
17 | return request(URL+"/api/disk/mkdir",{
18 | method : "POST",
19 | body : JSON.stringify({ parent_id,name })
20 | })
21 | }
22 |
23 | export function rename({ parent_id,source,target }){
24 | return request(URL+"/api/disk/rename",{
25 | method : "POST",
26 | body : JSON.stringify({ parent_id,source,target })
27 | });
28 | }
29 |
30 | export function remove({ id }){
31 | return request(URL+"/api/disk/remove",{
32 | method : "POST",
33 | body : JSON.stringify({id})
34 | });
35 | }
36 |
37 | export function move({ source_id,target_id }){
38 | return request(URL+"/api/disk/move",{
39 | method : "POST",
40 | body : JSON.stringify({
41 | source_id : parseInt(source_id),
42 | target_id : parseInt(target_id),
43 | })
44 | });
45 | }
46 |
47 | export function copy({ source_id,target_id }){
48 | return request(URL+"/api/disk/copy",{
49 | method : "POST",
50 | body : JSON.stringify({
51 | source_id : parseInt(source_id),
52 | target_id : parseInt(target_id),
53 | })
54 | });
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/services/DiskService/index.js:
--------------------------------------------------------------------------------
1 | import { fetch_list,fetch_tree,mkdir,rename,remove,move,copy } from "./DiskService"
2 |
3 | export default { fetch_list,fetch_tree,mkdir,rename,remove,move,copy }
--------------------------------------------------------------------------------
/src/tests/models/example-test.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import example from '../../models/example';
3 |
4 | describe('example', () => {
5 |
6 | describe('reducer', () => {
7 | it('it should save', () => {
8 | expect(example.reducers['example/save']({}, { payload: { a: 1 }})).toEqual({ a: 1 });
9 | });
10 | })
11 | });
12 |
--------------------------------------------------------------------------------
/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import fetch from 'dva/fetch';
2 |
3 | function parseJSON(response) {
4 | return response.json();
5 | }
6 |
7 | function checkStatus(response) {
8 | if (response.status >= 200 && response.status < 300) {
9 | return response;
10 | }
11 |
12 | const error = new Error(response.statusText);
13 | error.response = response;
14 | throw error;
15 | }
16 |
17 | /**
18 | * Requests a URL, returning a promise.
19 | *
20 | * @param {string} url The URL we want to request
21 | * @param {object} [options] The options we want to pass to "fetch"
22 | * @return {object} An object containing either "data" or "err"
23 | */
24 | export default function request(url, options) {
25 | return fetch(url, options)
26 | .then(checkStatus)
27 | .then(parseJSON)
28 | .then((data) => ({ data }))
29 | .catch((err) => ({ err }));
30 | }
31 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('atool-build/lib/webpack');
2 |
3 | module.exports = function(webpackConfig, env) {
4 | webpackConfig.babel.plugins.push('transform-runtime');
5 |
6 | // Support hmr
7 | if (env === 'development') {
8 | webpackConfig.devtool = '#eval';
9 | webpackConfig.babel.plugins.push('dva-hmr');
10 | } else {
11 | webpackConfig.babel.plugins.push('dev-expression');
12 | }
13 |
14 | // Don't extract common.js and common.css
15 | webpackConfig.plugins = webpackConfig.plugins.filter(function(plugin) {
16 | return !(plugin instanceof webpack.optimize.CommonsChunkPlugin);
17 | });
18 |
19 | // Support CSS Modules
20 | // Parse all less files as css module.
21 | webpackConfig.module.loaders.forEach(function(loader, index) {
22 | if (typeof loader.test === 'function' && loader.test.toString().indexOf('\\.less$') > -1) {
23 | loader.include = /node_modules/;
24 | loader.test = /\.less$/;
25 | }
26 | if (loader.test.toString() === '/\\.module\\.less$/') {
27 | loader.exclude = /node_modules/;
28 | loader.test = /\.less$/;
29 | }
30 | if (typeof loader.test === 'function' && loader.test.toString().indexOf('\\.css$') > -1) {
31 | loader.include = /node_modules/;
32 | loader.test = /\.css$/;
33 | }
34 | if (loader.test.toString() === '/\\.module\\.css$/') {
35 | loader.exclude = /node_modules/;
36 | loader.test = /\.css$/;
37 | }
38 | });
39 |
40 | return webpackConfig;
41 | };
42 |
--------------------------------------------------------------------------------