Scope.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import _ from 'lodash'
  2. import {invokeMethod} from "./utils";
  3. export class Scope {
  4. /**
  5. * 业务模块的唯一编号
  6. */
  7. id = _.uniqueId('scope_')
  8. /**
  9. * 模块文件路径(可以为空)
  10. */
  11. path
  12. /**
  13. * 一个 ExtJS 能接受的配置对象
  14. */
  15. vjson
  16. /**
  17. * 双向绑定的模型对象
  18. */
  19. viewModel
  20. /**
  21. * 构建完成之后的 Ext控件句柄
  22. */
  23. _handle
  24. /**
  25. * 与 Watch 装饰器配合使用.
  26. * viewModel 属性更改时触发成员方法
  27. */
  28. _watchList
  29. _addWatch(tplExpress, fn) {
  30. if (!this._watchList) {
  31. this._watchList = []
  32. }
  33. this._watchList.push({watch: tplExpress, fn})
  34. }
  35. _applyWatchList() {
  36. _.forEach(this._watchList, item => {
  37. this.viewModel.bind(item.watch, item.fn.bind(this))
  38. })
  39. }
  40. /**
  41. * 以对话框模式打开当前模块
  42. * @param sender 发送者(按钮或Scope对象)
  43. * @param option 覆盖选项(可以为空)
  44. */
  45. showDialog(sender, option) {
  46. const that = this
  47. const config = _.defaultsDeep({
  48. animateTarget: sender,
  49. listeners: {
  50. show(sender) {
  51. // 记录句柄
  52. if (sender && !that._handle) {
  53. that._handle = sender
  54. }
  55. // 调用onLoad回调
  56. that.onLoad()
  57. // 如果vjson中配置了 afterrender ,需要恢复状态
  58. invokeMethod(that.vjson.listeners?.show, that, arguments)
  59. }
  60. },
  61. }, option, that.vjson)
  62. const win = new Ext.Window(config);
  63. win.show();
  64. }
  65. /**
  66. * 以标签模式打开当前模块
  67. * @param option 覆盖选项(可以为空)
  68. */
  69. showPage(option) {
  70. const that = this
  71. const config = _.defaultsDeep({
  72. listeners: {
  73. added(sender) {
  74. // 记录句柄
  75. if (sender && !that._handle) {
  76. that._handle = sender
  77. }
  78. // 调用onLoad回调
  79. that.onLoad()
  80. // 如果vjson中配置了 afterrender ,需要恢复状态
  81. invokeMethod(that.vjson.listeners?.show, that, arguments)
  82. }
  83. },
  84. }, option, that.vjson)
  85. const tt = Ext.getCmp('TT')
  86. tt.addScope(this, config)
  87. return config
  88. }
  89. /**
  90. * 关闭对话框(或标签页)
  91. */
  92. close() {
  93. this._handle.close()
  94. }
  95. constructor({model, vjson}) {
  96. this.viewModel = new Ext.app.ViewModel(model);
  97. this.viewModel.yvanScope = this
  98. this._applyWatchList()
  99. const that = this
  100. this.vjson = _.defaultsDeep({
  101. closable: true,
  102. listeners: {
  103. afterrender(sender) {
  104. // 记录句柄
  105. if (sender && !that._handle) {
  106. that._handle = sender
  107. }
  108. // 调用 onRender 回调
  109. that.onRender()
  110. // 如果vjson中配置了 afterrender ,需要恢复状态
  111. invokeMethod(vjson.listeners?.afterrender, that, arguments)
  112. },
  113. activate(sender) {
  114. // 调用 onActivate 回调
  115. that.onActivate()
  116. const vm = sender.lookupViewModel()
  117. if (vm) {
  118. window['currentScope'] = sender.lookupViewModel().yvanScope
  119. }
  120. // 如果vjson中配置了 afterrender ,需要恢复状态
  121. invokeMethod(vjson.listeners?.activate, that, arguments)
  122. },
  123. deactivate(sender) {
  124. // 调用 onActivate 回调
  125. that.onDeactivate()
  126. // 如果vjson中配置了 afterrender ,需要恢复状态
  127. invokeMethod(vjson.listeners?.deactivate, that, arguments)
  128. },
  129. beforedestroy(sender) {
  130. // 调用 onBeforeDestroy 回调
  131. that.onBeforeDestroy()
  132. // 如果vjson中配置了 afterrender ,需要恢复状态
  133. invokeMethod(vjson.listeners?.beforedestroy, that, arguments)
  134. },
  135. beforeclose(sender) {
  136. // 调用 onActivate 回调
  137. that.onBeforeClose()
  138. // 如果vjson中配置了 afterrender ,需要恢复状态
  139. invokeMethod(vjson.listeners?.beforeclose, that, arguments)
  140. },
  141. destroy(sender) {
  142. // 调用 onActivate 回调
  143. that.onDestroy()
  144. // 销毁 viewModel
  145. that.viewModel.destroy()
  146. delete that.viewModel
  147. delete that.vjson
  148. delete that._watchList
  149. delete that._handle
  150. // 如果vjson中配置了 afterrender ,需要恢复状态
  151. invokeMethod(vjson.listeners?.destroy, that, arguments)
  152. },
  153. },
  154. yvanScope: this,
  155. viewModel: this.viewModel,
  156. referenceHolder: true,
  157. }, vjson)
  158. }
  159. /**
  160. * 获取所有设置过 Reference 名称的组件
  161. */
  162. get refs() {
  163. return this._handle.getReferences()
  164. }
  165. /**
  166. * 模块载入完成之后的回调
  167. */
  168. onLoad() {
  169. }
  170. /**
  171. * 渲染完成之后的回调
  172. */
  173. onRender() {
  174. }
  175. /**
  176. * 被激活时的回调(可能执行多次)
  177. */
  178. onActivate() {
  179. }
  180. /**
  181. * 进入未激活状态之前回调的函数
  182. */
  183. onDeactivate() {
  184. }
  185. /**
  186. * 关闭之前的回调(只有 tab 选项卡有这个选项)
  187. */
  188. onBeforeClose() {
  189. }
  190. /**
  191. * 组件被卸载之前的回调
  192. */
  193. onBeforeDestroy() {
  194. }
  195. /**
  196. * 组件卸载之后的回调
  197. */
  198. onDestroy() {
  199. }
  200. /**
  201. * 产生一个当前模块有效的唯一id
  202. * @param key 唯一编号
  203. */
  204. uid(key) {
  205. return this.id + key
  206. }
  207. }
  208. /**
  209. * 观察装饰器,viewModel 属性更改时触发成员方法
  210. * @param tplExpress tpl表达式,例如 "{form.f1}"
  211. */
  212. export function watch(tplExpress) {
  213. return function (target, propertyKey, pd) {
  214. target._addWatch(tplExpress, target[propertyKey])
  215. return target[propertyKey]
  216. }
  217. }