Scope.ts 8.8 KB

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