1 | ;
|
2 |
|
3 | exports.__esModule = true;
|
4 | exports.Sync = Sync;
|
5 | exports.Control = Control;
|
6 | exports.getControl = getControl;
|
7 |
|
8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
|
9 |
|
10 | var _model = require('./model');
|
11 |
|
12 | var _gfsReactTools = require('gfs-react-tools');
|
13 |
|
14 | var _gfsReactTools2 = _interopRequireDefault(_gfsReactTools);
|
15 |
|
16 | require('./utils');
|
17 |
|
18 | var _extend = require('extend');
|
19 |
|
20 | var _extend2 = _interopRequireDefault(_extend);
|
21 |
|
22 | /**
|
23 | * 控制器
|
24 | * @class Control
|
25 | * */
|
26 | var fetch = _gfsReactTools2['default'].fetch;
|
27 | exports.fetch = fetch;
|
28 | var controlList = {};
|
29 | //todo 异步action和数据实现
|
30 | //todo 异步ajax中间件
|
31 | var curl = {
|
32 | //use:
|
33 | /**
|
34 | * 删除store中某条数据
|
35 | * @method del
|
36 | * @param path {string} 需要被删除的属性地址,根据具体的对象结构,例如一个结构为:var data={name:'test',other:{age:18}}的对象,如果想删除age的值应该是这样:this.del('data.other.age')
|
37 | * @param modelName {string} model名字,默认是绑定model之后的modelname
|
38 | * @return Function
|
39 | * @example
|
40 | $Control(TestModel)
|
41 | class TestControl {
|
42 | delTest(data,dispatch,modelJson,model){
|
43 | this.del('age')
|
44 | }
|
45 | }
|
46 | */
|
47 | del: function del(path, data) {
|
48 | var modelName = arguments.length <= 2 || arguments[2] === undefined ? this.__modelName : arguments[2];
|
49 |
|
50 | path = path.indexOf('.') >= 0 ? path.split('.') : Array.prototype.concat.call([], path);
|
51 |
|
52 | return this.dispatch({
|
53 | type: this.getModelName('del', true, modelName), //`${DEFAULT}${DEFAULT_METHOD_FIX}${modelName}${DEFAULT_METHOD_FIX}del`,
|
54 | path: path,
|
55 | data: data
|
56 | });
|
57 | },
|
58 | /**
|
59 | * 更新store中某条数据,主要已合并为主,如果是想将新值覆盖旧值,请使用save方法
|
60 | * @method update
|
61 | * @param path {string} 需要被删除的属性地址,根据具体的对象结构,例如一个结构为:var data={name:'test',other:{age:18}}的对象,如果想修改age的值应该是这样:this.update('data.other.age',20)
|
62 | * @param data {string | objaect} 需要合并的值
|
63 | * @param modelName {string} model名字,默认是绑定model之后的modelname
|
64 | * @return Function
|
65 | * @example
|
66 | $Control(TestModel)
|
67 | class TestControl {
|
68 | updateTest(data,dispatch,modelJson,model){
|
69 | fetch('/test').then((data)=>{
|
70 | this.update('age',data.age)
|
71 | })
|
72 | }
|
73 | }
|
74 | */
|
75 | update: function update(path, data) {
|
76 | var modelName = arguments.length <= 2 || arguments[2] === undefined ? this.__modelName : arguments[2];
|
77 |
|
78 | if (arguments.length == 1) {
|
79 | data = arguments[0];
|
80 | path = '';
|
81 | } else {
|
82 | path = path.indexOf('.') >= 0 ? path.split('.') : Array.prototype.concat.call([], path);
|
83 | }
|
84 |
|
85 | return this.dispatch({
|
86 | type: this.getModelName('update', true, modelName), //`${DEFAULT}${DEFAULT_METHOD_FIX}${modelName}${DEFAULT_METHOD_FIX}update`,
|
87 | path: path,
|
88 | data: data
|
89 | });
|
90 | },
|
91 | /**
|
92 | * 更新store中某条数据,可自定义合并规则
|
93 | * @method updateWith
|
94 | * @param data {object} 需要合并的值
|
95 | * @param merge {function} 自定义合并规则方法
|
96 | * @param modelName {string} model名字,默认是绑定model之后的modelname
|
97 | * @return Function
|
98 | * @example
|
99 | $Control(TestModel)
|
100 | class TestControl {
|
101 | updateTest(data,dispatch,modelJson,model){
|
102 | return
|
103 | fetch('/test').then((data)=>{
|
104 | this.updateWith({
|
105 | names:['test','test1','test2']
|
106 | },function merger(prev,next){
|
107 | if( Immutable.List.isList(prev) && Immutable.List.isList(next)){
|
108 | return next
|
109 | }
|
110 | if(prev && prev.mergeWith){
|
111 | return prev.mergeWith(merger,next)
|
112 | }
|
113 | return next
|
114 | })
|
115 | })
|
116 |
|
117 | }
|
118 | }
|
119 | */
|
120 | updateWith: function updateWith(data, merge) {
|
121 | var modelName = arguments.length <= 2 || arguments[2] === undefined ? this.__modelName : arguments[2];
|
122 |
|
123 | if (data && data.modelName) {
|
124 | modelName = data.modelName.toLowerCase();
|
125 | data = data.data;
|
126 | }
|
127 | return this.dispatch({
|
128 | type: this.getModelName('updateWith', true, modelName), //`${DEFAULT}${DEFAULT_METHOD_FIX}${modelName}${DEFAULT_METHOD_FIX}update`,
|
129 | merge: merge || null,
|
130 | data: data
|
131 | });
|
132 | },
|
133 | /**
|
134 | * 插入store中某条数据
|
135 | * @method insert
|
136 | * @param path {string} 需要被删除的属性地址,根据具体的对象结构,例如一个结构为:var data={name:'test',other:{age:18}}的对象,如果想要在data中新增一些字段应该这样:this.insert({sex:'男'})
|
137 | * @param data {string | object} 需要保存的值,新的值会覆盖之前的值
|
138 | * @param isImmutable {boolean} 是否将值转换为Immutable类型,默认为false,如果更新的值为object类型建议设置为true
|
139 | * @param modelName {string} model名字,默认是绑定model之后的modelname
|
140 | * @return Function
|
141 | * @example
|
142 | $Control(TestModel)
|
143 | class TestControl {
|
144 | insertTest(data,dispatch,modelJson,model){
|
145 |
|
146 | fetch('/test').then((data)=>{
|
147 | this.insert({
|
148 | sex:'男'
|
149 | })
|
150 | })
|
151 |
|
152 | }
|
153 | }
|
154 | */
|
155 | insert: function insert(path, data) {
|
156 | var isImmutable = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
|
157 | var modelName = arguments.length <= 3 || arguments[3] === undefined ? this.__modelName : arguments[3];
|
158 |
|
159 | if (arguments.length == 1) {
|
160 | data = arguments[0];
|
161 | path = '';
|
162 | } else {
|
163 | path = path.indexOf('.') >= 0 ? path.split('.') : Array.prototype.concat.call([], path);
|
164 | }
|
165 |
|
166 | return this.dispatch({
|
167 | type: this.getModelName('update', true, modelName), //`${DEFAULT}${DEFAULT_METHOD_FIX}${modelName}${DEFAULT_METHOD_FIX}update`,
|
168 | path: path,
|
169 | data: data,
|
170 | isImmutable: isImmutable
|
171 | });
|
172 | },
|
173 | /**
|
174 | * 保存store中某条数据
|
175 | * @method save
|
176 | * @param path {string} 跟update一样
|
177 | * @param data {string | object} 需要保存的值,新的值会覆盖之前的值
|
178 | * @param isImmutable {boolean} 是否将值转换为Immutable类型,默认为false,如果更新的值为object类型建议设置为true
|
179 | * @param modelName {string} model名字,默认是绑定model之后的modelname
|
180 | * @return Function
|
181 | * @example
|
182 | $Control(TestModel)
|
183 | class TestControl {
|
184 | saveTest(data,dispatch,modelJson,model){
|
185 |
|
186 | fetch('/test').then((data)=>{
|
187 | this.save('age',data.age)
|
188 | })
|
189 |
|
190 | }
|
191 | }
|
192 | */
|
193 | save: function save(path, data) {
|
194 | var isImmutable = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2];
|
195 | var modelName = arguments.length <= 3 || arguments[3] === undefined ? this.__modelName : arguments[3];
|
196 |
|
197 | return this.dispatch({
|
198 | type: this.getModelName('save', true, modelName), //`${DEFAULT}${DEFAULT_METHOD_FIX}${modelName}${DEFAULT_METHOD_FIX}save`,
|
199 | path: path.indexOf('.') >= 0 ? path.split('.') : Array.prototype.concat.call([], path),
|
200 | data: data,
|
201 | isImmutable: isImmutable
|
202 | });
|
203 | }
|
204 | };
|
205 |
|
206 | //任意类型参数
|
207 | /**
|
208 | * 异步操作,<strong style="color:red">IE9以下不建议使用</strong>,Sync是一个装饰器(Decorator),用于装饰Control类中的方法,将原有的方法变成一个异步成功调用后执行结果方法,被装饰的方法需要返回数据或false,决定是否更新store刷新节点。
|
209 | * - 由Sync装饰后的方法,其作用域为Control,依然可以调用类中其他方法
|
210 | * - Sync参数error可以为Control中xxxError命名的方法替代,“xxx”命名规则必须与Sync装饰的方法名一致
|
211 | * - 被装饰后的方法在View中调用时传入的参数将已第二个为准,第一个参数将永远是异步执行后的结果
|
212 | * - 被装饰的方法名要和Model类中方法名对应
|
213 | * @method Sync
|
214 | * @param anywhere {object|string} 参数为一个字符串时,anywhere为url,当方法拥有2个参数,第一个参数作为url,第二个参数为object类型
|
215 | * @param anywhere.dataType {string} 数据返回类型 默认为json
|
216 | * @param anywhere.asyn {boolean} 是否为异步请求,默认为true
|
217 | * @param anywhere.method {string} 数据请求方式,默认为GET,可选值有:POST、GET、OPTION、DEL、PUT
|
218 | * @param anywhere.timeout {number} 请求超时时间,可选填
|
219 | * @param anywhere.credentials {object} 跨域是是否要包含cookie值,可选值:include
|
220 | * @param anywhere.error {function} 请求失败回调,可选
|
221 | * @param anywhere.header {object} 包含的请求头,可选
|
222 | * @param anywhere.body {object} 需要传递给服务端的属性字段值,可选
|
223 | * @param anywhere.cache {boolean} 请求数据是否缓存
|
224 | * @return function
|
225 | * @example
|
226 | * import {Sync,Control} from 'gfs-react-mvc'
|
227 | *
|
228 | * class TestControl{
|
229 | * constructor(){}
|
230 | * //这里由于@为文档关键符号,所以下面将以$代替
|
231 | * $Sync('/test',{
|
232 | * method:'get'
|
233 | * })
|
234 | * save(data){
|
235 | * //此处data是异步请求后服务器返回的结果
|
236 | * if(data){
|
237 | * //返回数据更新页面节点信息
|
238 | * return data
|
239 | * }
|
240 | * //不做任何改变
|
241 | * return false
|
242 | * }
|
243 | * $Sync('/del',{
|
244 | * method:'get'
|
245 | * })
|
246 | * del(data){
|
247 | * //此处data是异步请求后服务器返回的结果
|
248 | * if(data){
|
249 | * //返回数据更新页面节点信息
|
250 | * return {
|
251 | * //手动指定model对应方法
|
252 | * type:this.getModelName('del'),
|
253 | * data:data
|
254 | * }
|
255 | * }
|
256 | * //不做任何改变
|
257 | * return false
|
258 | * }
|
259 | * //也可直接使用
|
260 | * $Sync()
|
261 | * update(data){
|
262 | * //此处data是异步请求后服务器返回的结果
|
263 | * if(data){
|
264 | * //返回数据更新页面节点信息
|
265 | * return {
|
266 | * //手动指定model对应方法
|
267 | * type:this.getModelName('update'),
|
268 | * data:data
|
269 | * }
|
270 | * }
|
271 | * //不做任何改变
|
272 | * return false
|
273 | * }
|
274 | * }
|
275 | * */
|
276 |
|
277 | function Sync(anywhere) {
|
278 |
|
279 | var url = '';
|
280 | var opts = {};
|
281 | var error = null;
|
282 | //修正参数
|
283 | if (typeof anywhere === 'string') {
|
284 | url = anywhere;
|
285 | } else if (typeof anywhere === 'object') {
|
286 | url = anywhere.url;
|
287 | opts = anywhere;
|
288 | }
|
289 |
|
290 | if (arguments.length >= 2) {
|
291 | opts = arguments[1];
|
292 | }
|
293 | //todo error作用域无法指向target,target对象丢失,强制制定为undefined,解决作用域丢失问题
|
294 | if (opts.error) {
|
295 | error = opts.error;
|
296 | }
|
297 |
|
298 | return function (target, name, descriptor) {
|
299 |
|
300 | var fn = (function () {
|
301 | var success = arguments.length <= 0 || arguments[0] === undefined ? function () {} : arguments[0];
|
302 |
|
303 | var fn = success;
|
304 |
|
305 | return function () {
|
306 |
|
307 | var args = Array.prototype.slice.call(arguments);
|
308 | var methodArg = args[args.length - 1] || {};
|
309 |
|
310 | if (typeof methodArg === 'object' && methodArg.url) {
|
311 | url = methodArg.url;
|
312 | }
|
313 |
|
314 | return function (dispatch) {
|
315 | if (opts && typeof opts.method == 'undefined') {
|
316 | opts.method = 'get';
|
317 | }
|
318 | if (url) {
|
319 | fetch(url, _extend2['default'](opts, methodArg.url || methodArg.body ? methodArg : {})).then(function () {
|
320 | var result = fn.apply(target, Array.prototype.slice.call(arguments).concat(args));
|
321 | if (result instanceof Function) {
|
322 | result(dispatch);
|
323 | } else if (result && typeof result === 'object') {
|
324 | dispatch(_extend2['default'](result || {}, {
|
325 | type: '' + target.__modelName + _model.DEFAULT_METHOD_FIX + (result.type ? result.type : name),
|
326 | data: result.data ? result.data : {}
|
327 | }));
|
328 | }
|
329 | }, error || target[name + 'Error']);
|
330 | } else {
|
331 | var result = fn.apply(target, args);
|
332 | if (result && typeof result === 'object') {
|
333 | dispatch(_extend2['default'](result || {}, {
|
334 | type: '' + target.__modelName + _model.DEFAULT_METHOD_FIX + (result.type ? result.type : name),
|
335 | data: result.data ? result.data : {}
|
336 | }));
|
337 | }
|
338 | }
|
339 | };
|
340 | };
|
341 | })(descriptor.value);
|
342 |
|
343 | descriptor.value = fn;
|
344 | descriptor.enumerable = true;
|
345 | return descriptor;
|
346 | };
|
347 | }
|
348 |
|
349 | /**
|
350 | * 此方法是一个装饰器,只能用于类,被装饰后的类会变成对象列表(JSON)格式,主要目的是传递给组件使用,通过redux connect连接。
|
351 | * 被装饰的类将成为一个控制器,处理异步数据逻辑或业务逻辑,将数据传递给视图或服务器
|
352 | * @method Control
|
353 | * @param modelName {object} 实体类对象
|
354 | * @param loadingbar {Loadingbar} 废弃
|
355 | * @param mock {Mock} 废弃
|
356 | * @return object
|
357 | * @example
|
358 | * import {Sync,Control} from 'gfs-react-mvc'
|
359 | * import TestModel from '../model/TestModel'
|
360 | * //这里由于@为文档关键符号,所以下面将以$代替
|
361 | * //@Control(TestModel)
|
362 | * class TestControl{
|
363 | * constructor(){}
|
364 | * $action
|
365 | * changeAge(){
|
366 | *
|
367 | *
|
368 | * fetch('/test.json'[,params]).then((data)=>{
|
369 | * //control中默认提供update、del、insert、save四种操作数据方法,会根据不同的control名生成,如下根据testControl生成的方法testControlUpdate
|
370 | *
|
371 | * dispatch(this.testControlUpdate('age','ajax改变的age:'+data.age) )
|
372 | * })
|
373 | *
|
374 | * }
|
375 | * //不建议使用下列方式
|
376 | * //这里由于@为文档关键符号,所以下面将以$代替
|
377 | * $Sync('/test',{
|
378 | * method:'get'
|
379 | * })
|
380 | * $action
|
381 | * save(data){
|
382 | * //此处data是异步请求后服务器返回的结果
|
383 | * if(data){
|
384 | * //返回数据更新页面节点信息
|
385 | * return data
|
386 | * }
|
387 | * //不做任何改变
|
388 | * return false
|
389 | * }
|
390 | * }
|
391 | * */
|
392 |
|
393 | function Control(model, loadingbar, mock) {
|
394 | if (model === undefined) model = {};
|
395 |
|
396 | if (arguments.length === 2) {
|
397 | _gfsReactTools2['default'].addLoadingBar(loadingbar);
|
398 | }
|
399 |
|
400 | if (arguments.length === 3) {
|
401 | _gfsReactTools2['default'].addMock(mock);
|
402 | }
|
403 |
|
404 | return function (target) {
|
405 | //target = extend(target,curl)
|
406 | //let name = ''//target.name||''
|
407 | // let control = new target()
|
408 | //循环遍历方法,将返回
|
409 | //将方法的作用域改成对象本身
|
410 | //postmodel.toJS()
|
411 | var t = new target();
|
412 | var p = {};
|
413 | for (var item in t) {
|
414 | (function (item) {
|
415 | var fnName = item;
|
416 | p[fnName] = (function () {
|
417 | var args = Array.prototype.slice.call(arguments);
|
418 | var _this = this;
|
419 | return function (dispatch, store) {
|
420 | var modelJson = store()[model.modelName];
|
421 | _this.dispatch = dispatch;
|
422 | return t[fnName].apply(t, args.concat([dispatch, modelJson && typeof modelJson.toJS != 'undefined' ? modelJson.toJS() : null, modelJson || null]));
|
423 | };
|
424 | }).bind(t);
|
425 | })(item);
|
426 | // p[item] = t[item] instanceof Function ? t[item].bind(t ) : t[item]
|
427 | }
|
428 | model.controls = p;
|
429 | controlList[model.modelName] = model;
|
430 |
|
431 | for (var cItem in curl) {
|
432 | target.prototype[cItem] = curl[cItem];
|
433 | }
|
434 | target.prototype.__modelName = target.__modelName = model.modelName;
|
435 | /**
|
436 | * 获取model方法名全名,在未传任何值时返回方法前缀
|
437 | * @method getModelName
|
438 | * @param actionName {string} default='',方法名,可选
|
439 | * @param isDefault {boolean} 是否获取系统中提供的方法名,默认false,可选
|
440 | * @param modelName {string} model名字,可选
|
441 | * @return string
|
442 | */
|
443 | target.prototype.getModelName = target.getModelName = function () {
|
444 | var actionName = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
|
445 | var isDefault = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
|
446 | var modelName = arguments.length <= 2 || arguments[2] === undefined ? target.__modelName : arguments[2];
|
447 |
|
448 | return '' + (isDefault ? _model.DEFAULT + _model.DEFAULT_METHOD_FIX : '') + modelName + _model.DEFAULT_METHOD_FIX + actionName;
|
449 | };
|
450 | return model;
|
451 | //todo 解决对象私有属性访问,同样是对象丢失造成
|
452 | //return {...target.prototype}
|
453 | };
|
454 | }
|
455 |
|
456 | function getControl(modelName) {
|
457 |
|
458 | return controlList[modelName.toLowerCase()];
|
459 | } |
\ | No newline at end of file |