1. import { createReducer } from 'gfs-react-redux-twoway-binding'
  2. import Immutable from 'immutable'
  3. /**
  4. * 实体、数据模型,model中的方法和属性都该设置成静态类型
  5. * @class Model
  6. * */
  7. //需要一个队列保存model
  8. let __gfs_mvc_m_list = {}
  9. let __gfs_mvc_m_actiontypes = {}
  10.  
  11. export const DEFAULT_METHOD_FIX = '$$'
  12. export const DEFAULT='default'
  13.  
  14. function getField(data,path){
  15. try{
  16. var newpath = path.concat()
  17. for(var i=0,len=newpath.length,p,v;i<len;i++){
  18. //如果path不是最后一个
  19. if(i!=len){
  20. p = newpath.slice(0,i+1)
  21. v = data.getIn(p)
  22. if(!v ){
  23. data = typeof(v)=='undefined' ? data.mergeIn(p.slice(0,p.length-1),Immutable.fromJS({
  24. [p[p.length-1]]:{}
  25. }) ) : data.setIn(p,{})
  26. }
  27. }
  28. }
  29. }catch(ex){
  30. console && console.warn && (console.warn(ex) )
  31. }
  32.  
  33. return data
  34. }
  35.  
  36. function merger(prev,next){
  37. if( Immutable.List.isList(prev) && Immutable.List.isList(next)){
  38. return next
  39. }
  40. if(prev && prev.mergeWith){
  41. return prev.mergeWith(merger,next)
  42. }
  43. return next
  44. }
  45.  
  46. let curl = {
  47. del:function(data,action){
  48. return data.deleteIn(action.path)
  49. },
  50. update:function(data,action){
  51. data = getField(data,action.path)
  52. if(typeof(action.data) ==='string' && action.path){
  53. return data.setIn(action.path,action.data)
  54. }
  55. action.data = Immutable.fromJS(action.data)
  56. return action.path ? data.mergeDeepIn(action.path,action.data ) : data.mergeDeep(action.data )
  57. },
  58. updateWith:function(data,action){
  59. //data = getField(data,action.path)
  60. if(typeof(action.data) ==='string' && action.path){
  61. return data.setIn(action.path,action.data)
  62. }
  63. action.data = Immutable.fromJS(action.data)
  64. return data.mergeWith(action.merge ? action.merge:merger,action.data )
  65. },
  66. save:function(data,action){
  67. data = getField(data,action.path)
  68. return data.setIn(action.path,action.isImmutable ?Immutable.fromJS(action.data) : action.data)
  69. },
  70. insert:function(data,action){
  71. data = getField(data,action.path)
  72. return data.setIn(action.path,action.isImmutable ?Immutable.fromJS(action.data) : action.data)
  73. },
  74. query:function(data){
  75. return data
  76. },
  77. findOne:function(data,action){
  78. return data.getIn(action.path)
  79. },
  80. find:function(data,action){
  81. return data.getIn(action.path)
  82. }
  83. }
  84.  
  85. function implement(target={},modelName='',param={property:{},method:{}},fix=''){
  86. let property = param.property
  87. let method = param.method
  88.  
  89. if(fix){
  90. fix+=DEFAULT_METHOD_FIX
  91. }
  92. for(let item in target){
  93. if(!(target[item] instanceof Function) ){
  94. property[item] = target[item]
  95. }else{
  96. method[`${fix}${modelName}${DEFAULT_METHOD_FIX}${item}`] = target[item].bind(target)
  97. //__gfs_mvc_m_actiontypes[`${fix}${modelName}${DEFAULT_METHOD_FIX}${item}`] = `${fix}${modelName}${DEFAULT_METHOD_FIX}}${item}`
  98. }
  99.  
  100.  
  101. }
  102.  
  103. return {
  104. property:property,
  105. method:method
  106. }
  107. }
  108.  
  109. /**
  110. * 一个类装饰器,被装饰的类会变成store,默认不需要额外提供对数据操作的方法,在control中默认会提供del、update、insert等数据操作方法;如果有特殊需求无法满足使用场景可按照example中给出的方式自行编写数据处理方法<br />
  111. * <strong style="color:red">注意:model类中`__name`属性必须要有,这是为了能在各个component正常使用model必备的一个属性,必须小写,默认会在字符串后面添加上"model",例如:`static __name='test'`,那么在实际中运用应该是this.props.testmodel</strong>
  112. * @method Model
  113. * @param target {object} 被包装的对象
  114. * @example
  115. *
  116. * import {Model} from 'gfs-react-mvc'
  117. * //这里由于@为文档关键符号,所以下面将以$代替
  118. * //@Model
  119. * $Model
  120. class TestModel {
  121. //__name必须要有,这是为了能再各个component正常使用model必备的一个属性,必须小写
  122. static __name = 'testmodel'
  123. //数据模型
  124. static age = 20
  125. static xq = {}
  126. //可以自行定义数据操作方法,在control中通过
  127. //dispatch({
  128. // type:`testmodel$$save`,
  129. // data:data
  130. //})
  131. //这种方式变更数据,其中type值的组成是通过:类名(全小写)+ 方法名组成
  132. static save(data, action){
  133. if(action.data){
  134. return data.merge(Immutable.fromJS(action.data) )
  135. }
  136. }
  137. //dispatch({
  138. // type:`testmodel$$del`,
  139. // data:data
  140. //})
  141. static del(data, action){
  142. if(action.data){
  143. return data.merge(Immutable.fromJS(action.data) )
  144. }
  145. }
  146. }
  147. * */
  148. export function Model(target){
  149. let params={}
  150. //读取字段组成新的对象
  151. if(typeof(target.__name) == 'undefined' ){
  152. console && console.warn('[create model error] ','Model中必须存在__name属性,并赋予store名称,例如: static __name="testmodel"')
  153. return {
  154. modelName:'',
  155. store:null
  156. }
  157. }
  158. let modelName = target.__name.toLowerCase()
  159.  
  160. if(modelName.indexOf('model')<=-1){
  161. modelName+='model'
  162. }
  163. //取得属性或方法
  164. params = implement(target,modelName)
  165. params = implement(curl,modelName,params,DEFAULT)
  166. // params = implement(target.prototype,modelName,params)
  167.  
  168. let store = createReducer(modelName, Immutable.fromJS(params.property||{} ), params.method)
  169.  
  170. __gfs_mvc_m_list[`${modelName}`]=store
  171.  
  172. return {
  173. modelName:modelName,
  174. store:store
  175. }
  176.  
  177. }
  178.  
  179. export function getActionTypes(typeName){
  180. return __gfs_mvc_m_actiontypes[typeName]
  181. }
  182.  
  183. export function getModels(){
  184. return __gfs_mvc_m_list
  185. }
  186.  
  187. export function emptyModels(){
  188. __gfs_mvc_m_list = null
  189. //delete __gfs_mvc_m_list
  190. }
  191.  
  192.  
  193.