Scope.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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. const holder = sender?.lookupReferenceHolder()
  80. if (holder) {
  81. holder.add(win)
  82. }
  83. win.show();
  84. }
  85. /**
  86. * 以标签模式打开当前模块
  87. * @param vjsonOption 界面覆盖选项(可以为空)
  88. * @param dataOption 数据覆盖选项(可以为空)
  89. */
  90. showPage(vjsonOption, dataOption) {
  91. const that = this
  92. const vmodel = _.defaultsDeep({
  93. data: {}
  94. }, dataOption, that.model)
  95. this.viewModel = new Ext.app.ViewModel(vmodel);
  96. this.viewModel.yvanScope = this
  97. this._applyWatchList()
  98. const config = _.defaultsDeep({
  99. viewModel: this.viewModel,
  100. listeners: {
  101. added(sender) {
  102. // 记录句柄
  103. if (sender && !that._handle) {
  104. that._handle = sender
  105. }
  106. // 调用onLoad回调
  107. that.onLoad()
  108. // 如果vjson中配置了 afterrender ,需要恢复状态
  109. invokeMethod(that.vjson.listeners?.added, that, arguments)
  110. }
  111. },
  112. }, vjsonOption, that.vjson)
  113. const tt = Ext.getCmp('TT')
  114. tt.addScope(this, config)
  115. return config
  116. }
  117. /**
  118. * 直接渲染到元素
  119. * @param element 渲染目标
  120. * @param vjsonOption 界面覆盖选项(可以为空)
  121. * @param dataOption 数据覆盖选项(可以为空)
  122. */
  123. renderTo(element, vjsonOption, dataOption) {
  124. const that = this
  125. const vmodel = _.defaultsDeep({
  126. data: {}
  127. }, dataOption, that.model)
  128. this.viewModel = new Ext.app.ViewModel(vmodel);
  129. this.viewModel.yvanScope = this
  130. this._applyWatchList()
  131. const config = _.defaultsDeep({
  132. viewModel: this.viewModel,
  133. renderTo: element,
  134. listeners: {
  135. afterrender(sender) {
  136. // 记录句柄
  137. if (sender && !that._handle) {
  138. that._handle = sender
  139. }
  140. // 调用onLoad回调
  141. that.onLoad()
  142. // 如果vjson中配置了 afterrender ,需要恢复状态
  143. invokeMethod(that.vjson.listeners?.afterrender, that, arguments)
  144. }
  145. },
  146. }, vjsonOption, that.vjson)
  147. new Ext.container.Viewport(config);
  148. }
  149. /**
  150. * 关闭对话框(或标签页)
  151. */
  152. close() {
  153. this._handle.close()
  154. }
  155. /**
  156. * 获取 viewModel 里包含的数据(只读)
  157. */
  158. get data() {
  159. return this.viewModel.getData()
  160. }
  161. /**
  162. * 设置 viewModel 中的数据
  163. * 可以是 key, value 模式
  164. * 也可以是 {key:value} 模式
  165. */
  166. set(path, value) {
  167. return this.viewModel.set(path, value)
  168. }
  169. /**
  170. * 寻找模块内所有的 xtype 对应的对象
  171. * @param xtypeKey
  172. */
  173. down(xtypeKey) {
  174. return this._handle.down(xtypeKey)
  175. }
  176. /**
  177. * 获取所有设置过 Reference 名称的组件
  178. */
  179. get refs() {
  180. return this._handle.getReferences()
  181. }
  182. constructor({model, vjson}) {
  183. const that = this
  184. this.model = model
  185. this.vjson = _.defaultsDeep({
  186. closable: true,
  187. listeners: {
  188. afterrender(sender) {
  189. // 记录句柄
  190. if (sender && !that._handle) {
  191. that._handle = sender
  192. }
  193. // 调用 onRender 回调
  194. that.onRender()
  195. // 如果vjson中配置了 afterrender ,需要恢复状态
  196. invokeMethod(vjson.listeners?.afterrender, that, arguments)
  197. },
  198. activate(sender) {
  199. // 调用 onActivate 回调
  200. that.onActivate()
  201. const vm = sender.lookupViewModel()
  202. if (vm) {
  203. window['currentScope'] = sender.lookupViewModel().yvanScope
  204. }
  205. // 如果vjson中配置了 afterrender ,需要恢复状态
  206. invokeMethod(vjson.listeners?.activate, that, arguments)
  207. },
  208. deactivate(sender) {
  209. // 调用 onActivate 回调
  210. that.onDeactivate()
  211. // 如果vjson中配置了 afterrender ,需要恢复状态
  212. invokeMethod(vjson.listeners?.deactivate, that, arguments)
  213. },
  214. beforedestroy(sender) {
  215. // 调用 onBeforeDestroy 回调
  216. that.onBeforeDestroy()
  217. // 如果vjson中配置了 afterrender ,需要恢复状态
  218. invokeMethod(vjson.listeners?.beforedestroy, that, arguments)
  219. },
  220. beforeclose(sender) {
  221. // 调用 onActivate 回调
  222. that.onBeforeClose()
  223. // 如果vjson中配置了 afterrender ,需要恢复状态
  224. invokeMethod(vjson.listeners?.beforeclose, that, arguments)
  225. },
  226. destroy(sender) {
  227. // 调用 onActivate 回调
  228. that.onDestroy()
  229. // 销毁 viewModel
  230. that.viewModel.destroy()
  231. delete that.viewModel
  232. delete that.vjson
  233. delete that._watchList
  234. delete that._handle
  235. // 如果vjson中配置了 afterrender ,需要恢复状态
  236. invokeMethod(vjson.listeners?.destroy, that, arguments)
  237. },
  238. },
  239. yvanScope: this,
  240. referenceHolder: true,
  241. }, vjson)
  242. }
  243. /**
  244. * 模块载入完成之后的回调
  245. */
  246. onLoad() {
  247. }
  248. /**
  249. * 渲染完成之后的回调
  250. */
  251. onRender() {
  252. }
  253. /**
  254. * 被激活时的回调(可能执行多次)
  255. */
  256. onActivate() {
  257. }
  258. /**
  259. * 进入未激活状态之前回调的函数
  260. */
  261. onDeactivate() {
  262. }
  263. /**
  264. * 关闭之前的回调(只有 tab 选项卡有这个选项)
  265. */
  266. onBeforeClose() {
  267. }
  268. /**
  269. * 组件被卸载之前的回调
  270. */
  271. onBeforeDestroy() {
  272. }
  273. /**
  274. * 组件卸载之后的回调
  275. */
  276. onDestroy() {
  277. }
  278. }
  279. /**
  280. * 观察装饰器,viewModel 属性更改时触发成员方法
  281. * @param tplExpress tpl表达式,例如 "{form.f1}"
  282. */
  283. export function watch(tplExpress) {
  284. return function (target, propertyKey, pd) {
  285. target._addWatch(tplExpress, target[propertyKey])
  286. return target[propertyKey]
  287. }
  288. }