@visactor/vue-vtable 1.25.1-alpha.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/cjs/components/component/menu.js +3 -3
  2. package/cjs/components/component/tooltip.js +3 -3
  3. package/cjs/components/custom/checkBox.js +3 -3
  4. package/cjs/components/custom/group.js +3 -3
  5. package/cjs/components/custom/image.js +3 -3
  6. package/cjs/components/custom/radio.js +3 -3
  7. package/cjs/components/custom/tag.js +3 -3
  8. package/cjs/components/custom/text.js +3 -3
  9. package/cjs/components/custom/vtable-vue-attribute-plugin.js +622 -408
  10. package/cjs/components/list/list-column.js +3 -3
  11. package/cjs/components/pivot/pivot-column-dimension.js +3 -3
  12. package/cjs/components/pivot/pivot-column-header-title.js +3 -3
  13. package/cjs/components/pivot/pivot-corner.js +3 -3
  14. package/cjs/components/pivot/pivot-indicator.js +3 -3
  15. package/cjs/components/pivot/pivot-row-dimension.js +3 -3
  16. package/cjs/components/pivot/pivot-row-header-title.js +3 -3
  17. package/cjs/constants.js +1 -0
  18. package/cjs/edit/editor.js +209 -194
  19. package/cjs/edit/util.js +51 -31
  20. package/cjs/eventsUtils.js +97 -60
  21. package/cjs/hooks/useCellRender.js +27 -20
  22. package/cjs/hooks/useEditorRender.js +75 -52
  23. package/cjs/index.js +5 -5
  24. package/cjs/tables/base-table.vue.js +266 -237
  25. package/cjs/tables/chartModule.js +2 -2
  26. package/cjs/tables/list-table.vue.js +41 -39
  27. package/cjs/tables/pivot-chart.vue.js +35 -37
  28. package/cjs/tables/pivot-table.vue.js +36 -38
  29. package/cjs/utils/customLayoutUtils.js +109 -96
  30. package/cjs/utils/slotUtils.js +85 -88
  31. package/cjs/utils/stringUtils.js +14 -12
  32. package/cjs/utils/vnodeUtils.js +3 -2
  33. package/dist/vue-vtable.js +1715 -1358
  34. package/dist/vue-vtable.min.js +1 -1
  35. package/es/components/component/menu.js +3 -3
  36. package/es/components/component/tooltip.js +3 -3
  37. package/es/components/custom/checkBox.js +3 -3
  38. package/es/components/custom/group.js +3 -3
  39. package/es/components/custom/image.js +3 -3
  40. package/es/components/custom/radio.js +3 -3
  41. package/es/components/custom/tag.js +3 -3
  42. package/es/components/custom/text.js +3 -3
  43. package/es/components/custom/vtable-vue-attribute-plugin.js +622 -408
  44. package/es/components/list/list-column.js +3 -3
  45. package/es/components/pivot/pivot-column-dimension.js +3 -3
  46. package/es/components/pivot/pivot-column-header-title.js +3 -3
  47. package/es/components/pivot/pivot-corner.js +3 -3
  48. package/es/components/pivot/pivot-indicator.js +3 -3
  49. package/es/components/pivot/pivot-row-dimension.js +3 -3
  50. package/es/components/pivot/pivot-row-header-title.js +3 -3
  51. package/es/constants.js +1 -0
  52. package/es/edit/editor.js +209 -194
  53. package/es/edit/util.js +51 -31
  54. package/es/eventsUtils.js +97 -60
  55. package/es/hooks/useCellRender.js +27 -20
  56. package/es/hooks/useEditorRender.js +75 -52
  57. package/es/index.js +3 -3
  58. package/es/tables/base-table.vue.js +266 -237
  59. package/es/tables/chartModule.js +2 -2
  60. package/es/tables/list-table.vue.js +41 -39
  61. package/es/tables/pivot-chart.vue.js +35 -37
  62. package/es/tables/pivot-table.vue.js +36 -38
  63. package/es/utils/customLayoutUtils.js +109 -96
  64. package/es/utils/slotUtils.js +85 -88
  65. package/es/utils/stringUtils.js +14 -12
  66. package/es/utils/vnodeUtils.js +3 -2
  67. package/package.json +5 -5
  68. package/cjs/components/component/menu.d.ts +0 -14
  69. package/cjs/components/component/tooltip.d.ts +0 -11
  70. package/cjs/components/custom/checkBox.d.ts +0 -20
  71. package/cjs/components/custom/custom-layout.d.ts +0 -20
  72. package/cjs/components/custom/group.d.ts +0 -6
  73. package/cjs/components/custom/image.d.ts +0 -6
  74. package/cjs/components/custom/radio.d.ts +0 -17
  75. package/cjs/components/custom/tag.d.ts +0 -16
  76. package/cjs/components/custom/text.d.ts +0 -6
  77. package/cjs/components/custom/vtable-vue-attribute-plugin.d.ts +0 -62
  78. package/cjs/components/index.d.ts +0 -15
  79. package/cjs/components/list/list-column.d.ts +0 -7
  80. package/cjs/components/pivot/pivot-column-dimension.d.ts +0 -11
  81. package/cjs/components/pivot/pivot-column-header-title.d.ts +0 -7
  82. package/cjs/components/pivot/pivot-corner.d.ts +0 -7
  83. package/cjs/components/pivot/pivot-indicator.d.ts +0 -7
  84. package/cjs/components/pivot/pivot-row-dimension.d.ts +0 -11
  85. package/cjs/components/pivot/pivot-row-header-title.d.ts +0 -7
  86. package/cjs/constants.d.ts +0 -1
  87. package/cjs/edit/editor.d.ts +0 -50
  88. package/cjs/edit/index.d.ts +0 -2
  89. package/cjs/edit/util.d.ts +0 -4
  90. package/cjs/eventsUtils.d.ts +0 -120
  91. package/cjs/hooks/index.d.ts +0 -2
  92. package/cjs/hooks/useCellRender.d.ts +0 -2
  93. package/cjs/hooks/useEditorRender.d.ts +0 -2
  94. package/cjs/index.d.ts +0 -6
  95. package/cjs/tables/base-table.vue.d.ts +0 -543
  96. package/cjs/tables/chartModule.d.ts +0 -1
  97. package/cjs/tables/index.d.ts +0 -5
  98. package/cjs/tables/list-table.vue.d.ts +0 -38
  99. package/cjs/tables/pivot-chart.vue.d.ts +0 -38
  100. package/cjs/tables/pivot-table.vue.d.ts +0 -38
  101. package/cjs/utils/customLayoutUtils.d.ts +0 -5
  102. package/cjs/utils/slotUtils.d.ts +0 -28
  103. package/cjs/utils/stringUtils.d.ts +0 -2
  104. package/cjs/utils/vnodeUtils.d.ts +0 -1
  105. package/cjs/utils.d.ts +0 -4
  106. package/es/components/component/menu.d.ts +0 -14
  107. package/es/components/component/tooltip.d.ts +0 -11
  108. package/es/components/custom/checkBox.d.ts +0 -20
  109. package/es/components/custom/custom-layout.d.ts +0 -20
  110. package/es/components/custom/group.d.ts +0 -6
  111. package/es/components/custom/image.d.ts +0 -6
  112. package/es/components/custom/radio.d.ts +0 -17
  113. package/es/components/custom/tag.d.ts +0 -16
  114. package/es/components/custom/text.d.ts +0 -6
  115. package/es/components/custom/vtable-vue-attribute-plugin.d.ts +0 -62
  116. package/es/components/index.d.ts +0 -15
  117. package/es/components/list/list-column.d.ts +0 -7
  118. package/es/components/pivot/pivot-column-dimension.d.ts +0 -11
  119. package/es/components/pivot/pivot-column-header-title.d.ts +0 -7
  120. package/es/components/pivot/pivot-corner.d.ts +0 -7
  121. package/es/components/pivot/pivot-indicator.d.ts +0 -7
  122. package/es/components/pivot/pivot-row-dimension.d.ts +0 -11
  123. package/es/components/pivot/pivot-row-header-title.d.ts +0 -7
  124. package/es/constants.d.ts +0 -1
  125. package/es/edit/editor.d.ts +0 -50
  126. package/es/edit/index.d.ts +0 -2
  127. package/es/edit/util.d.ts +0 -4
  128. package/es/eventsUtils.d.ts +0 -120
  129. package/es/hooks/index.d.ts +0 -2
  130. package/es/hooks/useCellRender.d.ts +0 -2
  131. package/es/hooks/useEditorRender.d.ts +0 -2
  132. package/es/index.d.ts +0 -6
  133. package/es/tables/base-table.vue.d.ts +0 -543
  134. package/es/tables/chartModule.d.ts +0 -1
  135. package/es/tables/index.d.ts +0 -5
  136. package/es/tables/list-table.vue.d.ts +0 -38
  137. package/es/tables/pivot-chart.vue.d.ts +0 -38
  138. package/es/tables/pivot-table.vue.d.ts +0 -38
  139. package/es/utils/customLayoutUtils.d.ts +0 -5
  140. package/es/utils/slotUtils.d.ts +0 -28
  141. package/es/utils/stringUtils.d.ts +0 -2
  142. package/es/utils/vnodeUtils.d.ts +0 -1
  143. package/es/utils.d.ts +0 -4
@@ -23,1426 +23,1783 @@
23
23
 
24
24
  var VTable__namespace = /*#__PURE__*/_interopNamespaceDefault(VTable);
25
25
 
26
- function toCamelCase(str) {
27
- return str.replace(/-([a-z])/g, g => g[1].toUpperCase());
28
- }
29
- function convertPropsToCamelCase(props) {
30
- const newProps = {};
31
- for (const key in props) {
32
- if (props.hasOwnProperty(key)) {
33
- const camelCaseKey = toCamelCase(key);
34
- newProps[camelCaseKey] = props[key];
35
- }
36
- }
37
- return newProps;
26
+ // 将连字符形式的字符串转换为驼峰形式
27
+ function toCamelCase(str) {
28
+ return str.replace(/-([a-z])/g, g => g[1].toUpperCase());
29
+ }
30
+ // vnode.props 中的所有属性名转换为驼峰形式
31
+ function convertPropsToCamelCase(props) {
32
+ const newProps = {};
33
+ for (const key in props) {
34
+ if (props.hasOwnProperty(key)) {
35
+ const camelCaseKey = toCamelCase(key);
36
+ newProps[camelCaseKey] = props[key];
37
+ }
38
+ }
39
+ return newProps;
38
40
  }
39
41
 
40
- function flattenVNodes(vnodes) {
41
- return vnodes.flatMap(vnode => (Array.isArray(vnode.children) ? flattenVNodes(vnode.children) : vnode));
42
+ // 展平嵌套的虚拟节点
43
+ function flattenVNodes(vnodes) {
44
+ return vnodes.flatMap(vnode => (Array.isArray(vnode.children) ? flattenVNodes(vnode.children) : vnode));
42
45
  }
43
46
 
44
- function isEventProp(key, props) {
45
- return key.startsWith('on') && vutils.isFunction(props[key]);
46
- }
47
- function createCustomLayout(children, isHeader, args) {
48
- const componentMap = {
49
- Group: VTable__namespace.CustomLayout.Group,
50
- Image: VTable__namespace.CustomLayout.Image,
51
- Text: VTable__namespace.CustomLayout.Text,
52
- Tag: VTable__namespace.CustomLayout.Tag,
53
- Radio: VTable__namespace.CustomLayout.Radio,
54
- CheckBox: VTable__namespace.CustomLayout.CheckBox
55
- };
56
- function createComponent(child) {
57
- if (!child) {
58
- return null;
59
- }
60
- const { type, children: childChildren } = child;
61
- const props = convertPropsToCamelCase(child.props);
62
- const componentName = type?.symbol || type?.name;
63
- const ComponentClass = componentMap[componentName];
64
- if (!ComponentClass) {
65
- return null;
66
- }
67
- const component = new ComponentClass({ ...props });
68
- bindComponentEvents(component, props);
69
- const subChildren = resolveChildren(childChildren);
70
- if (vutils.isObject(props?.vue)) {
71
- const { element } = props.vue;
72
- let targetVNode = element ?? subChildren.find(node => node?.type !== Symbol.for('v-cmt'));
73
- if (vue.isVNode(targetVNode)) {
74
- targetVNode = !targetVNode.key
75
- ? vue.cloneVNode(targetVNode, { key: `row_${args.row}_col_${args.col}` })
76
- : targetVNode;
77
- }
78
- else {
79
- targetVNode = null;
80
- }
81
- Object.assign(child.props.vue, {
82
- element: targetVNode,
83
- container: isHeader ? args?.table?.headerDomContainer : args?.table?.bodyDomContainer
84
- });
85
- return component;
86
- }
87
- subChildren.forEach((subChild) => {
88
- const subComponent = createComponent(subChild);
89
- if (subComponent) {
90
- component.add(subComponent);
91
- }
92
- else if (subChild.type === Symbol.for('v-fgt')) {
93
- subChild.children.forEach((nestedChild) => {
94
- const nestedComponent = createComponent(nestedChild);
95
- if (nestedComponent) {
96
- component.add(nestedComponent);
97
- }
98
- });
99
- }
100
- });
101
- return component;
102
- }
103
- function resolveChildren(childChildren) {
104
- return childChildren?.default?.() || childChildren || [];
105
- }
106
- function bindComponentEvents(component, props) {
107
- Object.keys(props).forEach(key => {
108
- if (isEventProp(key, props)) {
109
- let eventName;
110
- if (key.startsWith('on')) {
111
- eventName = key.slice(2).toLowerCase();
112
- }
113
- else {
114
- eventName = toCamelCase(key.slice(2)).toLowerCase();
115
- }
116
- component.addEventListener(eventName, props[key]);
117
- }
118
- });
119
- }
120
- return { rootComponent: createComponent(children) };
121
- }
122
- function createCustomLayoutHandler(children, isHeader) {
123
- return (args) => {
124
- const { table, row, col, rect } = args;
125
- const record = table.getCellOriginRecord(col, row);
126
- const { height, width } = rect ?? table.getCellRect(col, row);
127
- const customLayoutKey = isHeader ? 'headerCustomLayout' : 'customLayout';
128
- if (!children[customLayoutKey]) {
129
- return null;
130
- }
131
- const rootContainer = children[customLayoutKey]({ table, row, col, rect, record, height, width })[0];
132
- const { rootComponent } = createCustomLayout(rootContainer, isHeader, args);
133
- return {
134
- rootContainer: rootComponent,
135
- renderDefault: false
136
- };
137
- };
47
+ // 检查属性是否为事件
48
+ function isEventProp(key, props) {
49
+ return key.startsWith('on') && vutils.isFunction(props[key]);
50
+ }
51
+ // 创建自定义布局
52
+ function createCustomLayout(children, isHeader, args) {
53
+ // 组件映射
54
+ const componentMap = {
55
+ Group: VTable__namespace.CustomLayout.Group,
56
+ Image: VTable__namespace.CustomLayout.Image,
57
+ Text: VTable__namespace.CustomLayout.Text,
58
+ Tag: VTable__namespace.CustomLayout.Tag,
59
+ Radio: VTable__namespace.CustomLayout.Radio,
60
+ CheckBox: VTable__namespace.CustomLayout.CheckBox
61
+ };
62
+ // 创建组件的函数
63
+ function createComponent(child) {
64
+ var _a, _b;
65
+ if (!child) {
66
+ return null;
67
+ }
68
+ const { type, children: childChildren } = child;
69
+ const props = convertPropsToCamelCase(child.props);
70
+ const componentName = (type === null || type === void 0 ? void 0 : type.symbol) || (type === null || type === void 0 ? void 0 : type.name);
71
+ const ComponentClass = componentMap[componentName];
72
+ if (!ComponentClass) {
73
+ return null;
74
+ }
75
+ // 创建组件实例
76
+ const component = new ComponentClass(Object.assign({}, props));
77
+ // 绑定组件事件
78
+ bindComponentEvents(component, props);
79
+ // 递归创建子组件
80
+ const subChildren = resolveChildren(childChildren);
81
+ if (vutils.isObject(props === null || props === void 0 ? void 0 : props.vue)) {
82
+ // vue 自定义节点:无需继续循环子节点
83
+ const { element } = props.vue;
84
+ let targetVNode = element !== null && element !== void 0 ? element : subChildren.find(node => (node === null || node === void 0 ? void 0 : node.type) !== Symbol.for('v-cmt'));
85
+ if (vue.isVNode(targetVNode)) {
86
+ // node 标记 key 增加唯一项标记,避免重复渲染
87
+ targetVNode = !targetVNode.key
88
+ ? vue.cloneVNode(targetVNode, { key: `row_${args.row}_col_${args.col}` })
89
+ : targetVNode;
90
+ }
91
+ else {
92
+ targetVNode = null;
93
+ }
94
+ Object.assign(child.props.vue, {
95
+ element: targetVNode,
96
+ // 不接入外部指定
97
+ container: isHeader ? (_a = args === null || args === void 0 ? void 0 : args.table) === null || _a === void 0 ? void 0 : _a.headerDomContainer : (_b = args === null || args === void 0 ? void 0 : args.table) === null || _b === void 0 ? void 0 : _b.bodyDomContainer
98
+ });
99
+ return component;
100
+ }
101
+ subChildren.forEach((subChild) => {
102
+ const subComponent = createComponent(subChild);
103
+ if (subComponent) {
104
+ component.add(subComponent);
105
+ }
106
+ else if (subChild.type === Symbol.for('v-fgt')) {
107
+ subChild.children.forEach((nestedChild) => {
108
+ const nestedComponent = createComponent(nestedChild);
109
+ if (nestedComponent) {
110
+ component.add(nestedComponent);
111
+ }
112
+ });
113
+ }
114
+ });
115
+ return component;
116
+ }
117
+ // 处理子节点
118
+ function resolveChildren(childChildren) {
119
+ var _a;
120
+ return ((_a = childChildren === null || childChildren === void 0 ? void 0 : childChildren.default) === null || _a === void 0 ? void 0 : _a.call(childChildren)) || childChildren || [];
121
+ }
122
+ // 绑定组件事件
123
+ function bindComponentEvents(component, props) {
124
+ Object.keys(props).forEach(key => {
125
+ if (isEventProp(key, props)) {
126
+ let eventName;
127
+ if (key.startsWith('on')) {
128
+ eventName = key.slice(2).toLowerCase(); // 去掉'on'前缀并转换为小写
129
+ }
130
+ else {
131
+ eventName = toCamelCase(key.slice(2)).toLowerCase(); // 转换为camelCase
132
+ }
133
+ component.addEventListener(eventName, props[key]);
134
+ }
135
+ });
136
+ }
137
+ // 返回root组件和refs
138
+ return { rootComponent: createComponent(children) };
139
+ }
140
+ function createCustomLayoutHandler(children, isHeader) {
141
+ return (args) => {
142
+ const { table, row, col, rect } = args;
143
+ const record = table.getCellOriginRecord(col, row);
144
+ const { height, width } = rect !== null && rect !== void 0 ? rect : table.getCellRect(col, row);
145
+ const customLayoutKey = isHeader ? 'headerCustomLayout' : 'customLayout';
146
+ if (!children[customLayoutKey]) {
147
+ return null;
148
+ }
149
+ const rootContainer = children[customLayoutKey]({ table, row, col, rect, record, height, width })[0];
150
+ const { rootComponent } = createCustomLayout(rootContainer, isHeader, args);
151
+ return {
152
+ rootContainer: rootComponent,
153
+ renderDefault: false
154
+ };
155
+ };
138
156
  }
139
157
 
140
- class DynamicRenderEditor {
141
- wrapContainer;
142
- tableContainer;
143
- currentValue;
144
- nodeMap;
145
- currentContext;
146
- constructor(currentContext) {
147
- this.currentContext = currentContext;
148
- this.tableContainer = null;
149
- this.currentValue = null;
150
- this.wrapContainer = null;
151
- this.nodeMap = new Map();
152
- }
153
- registerNode(tableId, key, getNode) {
154
- if (!vutils.isValid(tableId) || !vutils.isValid(key) || typeof getNode !== 'function') {
155
- return;
156
- }
157
- if (!this.nodeMap.has(tableId)) {
158
- this.nodeMap.set(tableId, new Map());
159
- }
160
- this.nodeMap.get(tableId).set(key, getNode);
161
- }
162
- getNode(tableId, key) {
163
- return this.nodeMap.get(tableId)?.get(key);
164
- }
165
- removeNode(tableId) {
166
- this.nodeMap.delete(tableId);
167
- }
168
- release(tableId) {
169
- if (!vutils.isValid(tableId)) {
170
- this.nodeMap.clear();
171
- }
172
- else {
173
- this.removeNode(tableId);
174
- }
175
- }
176
- async onStart(editorContext) {
177
- const { value } = editorContext;
178
- this.setValue(value);
179
- if (!(await this.createElement(editorContext))) {
180
- return;
181
- }
182
- }
183
- async createElement(editorContext) {
184
- const { row, col, value, table, container, referencePosition } = editorContext;
185
- if (!container) {
186
- return false;
187
- }
188
- const define = table.getBodyColumnDefine(col, row);
189
- const { editConfig } = define || {};
190
- const { id } = table;
191
- const key = this.getColumnKeyField(define);
192
- if (!vutils.isValid(key) || !vutils.isValid(id)) {
193
- return false;
194
- }
195
- if (typeof editConfig?.editBefore === 'function') {
196
- const v = await editConfig.editBefore(editorContext);
197
- if (!v) {
198
- table.showTooltip(col, row, {
199
- content: editConfig.disablePrompt || 'This field is not allowed to be edited',
200
- referencePosition: { rect: referencePosition?.rect, placement: VTable.TYPES.Placement.top },
201
- style: {
202
- bgColor: 'black',
203
- color: 'white',
204
- arrowMark: true
205
- },
206
- disappearDelay: 1000
207
- });
208
- return false;
209
- }
210
- }
211
- const record = table?.getCellOriginRecord(col, row);
212
- const renderVNodeFn = this.getNode(id, key);
213
- if (!renderVNodeFn) {
214
- return false;
215
- }
216
- const vnode = vue.h(renderVNodeFn, {
217
- row,
218
- col,
219
- value,
220
- refValue: vue.customRef((track, trigger) => {
221
- return {
222
- get: () => {
223
- track();
224
- return this.getValue();
225
- },
226
- set: value => {
227
- this.setValue(value);
228
- trigger();
229
- }
230
- };
231
- }),
232
- record,
233
- table,
234
- onChange: (value) => this.setValue(value)
235
- });
236
- if (!vnode || !vue.isVNode(vnode)) {
237
- return false;
238
- }
239
- this.checkToPassAppContext(vnode, table);
240
- const wrapContainer = document.createElement('div');
241
- wrapContainer.style.position = 'absolute';
242
- wrapContainer.style.width = '100%';
243
- wrapContainer.style.boxSizing = 'border-box';
244
- const { bgColor } = table.getCellStyle(col, row) || {};
245
- wrapContainer.style.backgroundColor = bgColor || '#FFFFFF';
246
- this.wrapContainer = wrapContainer;
247
- this.tableContainer = container;
248
- this.tableContainer.appendChild(wrapContainer);
249
- vue.render(vnode, wrapContainer);
250
- if (referencePosition?.rect) {
251
- this.adjustPosition(referencePosition.rect);
252
- }
253
- return true;
254
- }
255
- checkToPassAppContext(vnode, table) {
256
- try {
257
- const userAppContext = table.options?.customConfig?.getVueUserAppContext?.() ?? this.currentContext;
258
- if (!!userAppContext?.components && !!userAppContext?.directives) {
259
- vnode.appContext = userAppContext;
260
- }
261
- }
262
- catch (error) { }
263
- }
264
- getColumnKeyField(column) {
265
- const { field, key } = column || {};
266
- return vutils.isValid(key) ? key : field;
267
- }
268
- getValue() {
269
- return this.currentValue;
270
- }
271
- setValue(value) {
272
- this.currentValue = value;
273
- }
274
- adjustPosition(rect) {
275
- if (this.wrapContainer) {
276
- this.wrapContainer.style.top = `${rect.top}px`;
277
- this.wrapContainer.style.left = `${rect.left}px`;
278
- this.wrapContainer.style.width = `${rect.width}px`;
279
- this.wrapContainer.style.height = `${rect.height}px`;
280
- }
281
- }
282
- async validateValue(value, oldValue, editCell, table) {
283
- const { col, row } = editCell || {};
284
- if (!vutils.isValid(col) || !vutils.isValid(row)) {
285
- return true;
286
- }
287
- const define = table.getBodyColumnDefine(col, row);
288
- const { editConfig } = define || {};
289
- if (typeof editConfig?.validateValue === 'function') {
290
- const validate = await editConfig.validateValue({ col, row, value, oldValue, table });
291
- if (validate === false) {
292
- const rect = table.getVisibleCellRangeRelativeRect({ col, row });
293
- table.showTooltip(col, row, {
294
- content: editConfig.invalidPrompt || 'invalid',
295
- referencePosition: { rect, placement: VTable.TYPES.Placement.top },
296
- style: {
297
- bgColor: 'red',
298
- color: 'white',
299
- arrowMark: true
300
- },
301
- disappearDelay: 1000
302
- });
303
- return false;
304
- }
305
- return validate;
306
- }
307
- return true;
308
- }
309
- onEnd() {
310
- if (this.wrapContainer && this.tableContainer) {
311
- vue.render(null, this.wrapContainer);
312
- this.tableContainer.removeChild(this.wrapContainer);
313
- }
314
- this.wrapContainer = null;
315
- this.tableContainer = null;
316
- }
317
- isEditorElement(target) {
318
- return this.wrapContainer?.contains(target) || this.isClickEditorElement(target);
319
- }
320
- isClickEditorElement(target) {
321
- while (target) {
322
- if (target.classList && target.classList.contains('table-editor-element')) {
323
- return true;
324
- }
325
- target = target.parentNode;
326
- }
327
- return false;
328
- }
158
+ /**
159
+ * @description: 自定义渲染式编辑器
160
+ */
161
+ class DynamicRenderEditor {
162
+ constructor(currentContext) {
163
+ this.currentContext = currentContext;
164
+ this.tableContainer = null;
165
+ this.currentValue = null;
166
+ this.wrapContainer = null;
167
+ this.nodeMap = new Map();
168
+ }
169
+ registerNode(tableId, key, getNode) {
170
+ if (!vutils.isValid(tableId) || !vutils.isValid(key) || typeof getNode !== 'function') {
171
+ return;
172
+ }
173
+ if (!this.nodeMap.has(tableId)) {
174
+ this.nodeMap.set(tableId, new Map());
175
+ }
176
+ this.nodeMap.get(tableId).set(key, getNode);
177
+ }
178
+ getNode(tableId, key) {
179
+ var _a;
180
+ return (_a = this.nodeMap.get(tableId)) === null || _a === void 0 ? void 0 : _a.get(key);
181
+ }
182
+ removeNode(tableId) {
183
+ this.nodeMap.delete(tableId);
184
+ }
185
+ release(tableId) {
186
+ if (!vutils.isValid(tableId)) {
187
+ this.nodeMap.clear();
188
+ }
189
+ else {
190
+ this.removeNode(tableId);
191
+ }
192
+ }
193
+ async onStart(editorContext) {
194
+ const { value } = editorContext;
195
+ // 先设置初始值(因为校验不通过也会走正常流程)
196
+ this.setValue(value);
197
+ if (!(await this.createElement(editorContext))) {
198
+ return;
199
+ }
200
+ }
201
+ async createElement(editorContext) {
202
+ const { row, col, value, table, container, referencePosition } = editorContext;
203
+ if (!container) {
204
+ return false;
205
+ }
206
+ const define = table.getBodyColumnDefine(col, row);
207
+ const { editConfig } = define || {};
208
+ const { id } = table;
209
+ const key = this.getColumnKeyField(define);
210
+ if (!vutils.isValid(key) || !vutils.isValid(id)) {
211
+ return false;
212
+ }
213
+ if (typeof (editConfig === null || editConfig === void 0 ? void 0 : editConfig.editBefore) === 'function') {
214
+ // 编辑前校验
215
+ const v = await editConfig.editBefore(editorContext);
216
+ if (!v) {
217
+ table.showTooltip(col, row, {
218
+ // TODO 多语言
219
+ content: editConfig.disablePrompt || 'This field is not allowed to be edited',
220
+ referencePosition: { rect: referencePosition === null || referencePosition === void 0 ? void 0 : referencePosition.rect, placement: VTable.TYPES.Placement.top },
221
+ style: {
222
+ bgColor: 'black',
223
+ color: 'white',
224
+ arrowMark: true
225
+ },
226
+ disappearDelay: 1000
227
+ });
228
+ return false;
229
+ }
230
+ }
231
+ const record = table === null || table === void 0 ? void 0 : table.getCellOriginRecord(col, row);
232
+ const renderVNodeFn = this.getNode(id, key);
233
+ if (!renderVNodeFn) {
234
+ return false;
235
+ }
236
+ const vnode = vue.h(renderVNodeFn, {
237
+ row,
238
+ col,
239
+ value,
240
+ refValue: vue.customRef((track, trigger) => {
241
+ return {
242
+ get: () => {
243
+ track();
244
+ return this.getValue();
245
+ },
246
+ set: value => {
247
+ this.setValue(value);
248
+ trigger();
249
+ }
250
+ };
251
+ }),
252
+ record,
253
+ table,
254
+ onChange: (value) => this.setValue(value)
255
+ });
256
+ if (!vnode || !vue.isVNode(vnode)) {
257
+ return false;
258
+ }
259
+ this.checkToPassAppContext(vnode, table);
260
+ // 创建包裹容器
261
+ const wrapContainer = document.createElement('div');
262
+ wrapContainer.style.position = 'absolute';
263
+ wrapContainer.style.width = '100%';
264
+ wrapContainer.style.boxSizing = 'border-box';
265
+ const { bgColor } = table.getCellStyle(col, row) || {};
266
+ wrapContainer.style.backgroundColor = bgColor || '#FFFFFF';
267
+ this.wrapContainer = wrapContainer;
268
+ this.tableContainer = container;
269
+ this.tableContainer.appendChild(wrapContainer);
270
+ vue.render(vnode, wrapContainer);
271
+ // 位置同步
272
+ if (referencePosition === null || referencePosition === void 0 ? void 0 : referencePosition.rect) {
273
+ this.adjustPosition(referencePosition.rect);
274
+ }
275
+ return true;
276
+ }
277
+ /**
278
+ * @description: 校验并传递上下文
279
+ * @param {VNode} vnode
280
+ * @param {any} table
281
+ * @return {*}
282
+ */
283
+ checkToPassAppContext(vnode, table) {
284
+ var _a, _b, _c, _d;
285
+ try {
286
+ const userAppContext = (_d = (_c = (_b = (_a = table.options) === null || _a === void 0 ? void 0 : _a.customConfig) === null || _b === void 0 ? void 0 : _b.getVueUserAppContext) === null || _c === void 0 ? void 0 : _c.call(_b)) !== null && _d !== void 0 ? _d : this.currentContext;
287
+ // 简单校验合法性
288
+ if (!!(userAppContext === null || userAppContext === void 0 ? void 0 : userAppContext.components) && !!(userAppContext === null || userAppContext === void 0 ? void 0 : userAppContext.directives)) {
289
+ vnode.appContext = userAppContext;
290
+ }
291
+ }
292
+ catch (error) { }
293
+ }
294
+ /**
295
+ * @description: 获取渲染式编辑器的列配置主键
296
+ * @param {any} column
297
+ * @return {*}
298
+ */
299
+ getColumnKeyField(column) {
300
+ const { field, key } = column || {};
301
+ // 兼容取 field
302
+ return vutils.isValid(key) ? key : field;
303
+ }
304
+ getValue() {
305
+ return this.currentValue;
306
+ }
307
+ setValue(value) {
308
+ this.currentValue = value;
309
+ }
310
+ adjustPosition(rect) {
311
+ if (this.wrapContainer) {
312
+ this.wrapContainer.style.top = `${rect.top}px`;
313
+ this.wrapContainer.style.left = `${rect.left}px`;
314
+ this.wrapContainer.style.width = `${rect.width}px`;
315
+ this.wrapContainer.style.height = `${rect.height}px`;
316
+ }
317
+ }
318
+ async validateValue(value, oldValue, editCell, table) {
319
+ const { col, row } = editCell || {};
320
+ if (!vutils.isValid(col) || !vutils.isValid(row)) {
321
+ return true;
322
+ }
323
+ const define = table.getBodyColumnDefine(col, row);
324
+ const { editConfig } = define || {};
325
+ if (typeof (editConfig === null || editConfig === void 0 ? void 0 : editConfig.validateValue) === 'function') {
326
+ const validate = await editConfig.validateValue({ col, row, value, oldValue, table });
327
+ if (validate === false) {
328
+ const rect = table.getVisibleCellRangeRelativeRect({ col, row });
329
+ table.showTooltip(col, row, {
330
+ content: editConfig.invalidPrompt || 'invalid',
331
+ referencePosition: { rect, placement: VTable.TYPES.Placement.top },
332
+ style: {
333
+ bgColor: 'red',
334
+ color: 'white',
335
+ arrowMark: true
336
+ },
337
+ disappearDelay: 1000
338
+ });
339
+ return false;
340
+ }
341
+ return validate;
342
+ }
343
+ return true;
344
+ }
345
+ onEnd() {
346
+ if (this.wrapContainer && this.tableContainer) {
347
+ vue.render(null, this.wrapContainer);
348
+ this.tableContainer.removeChild(this.wrapContainer);
349
+ }
350
+ this.wrapContainer = null;
351
+ this.tableContainer = null;
352
+ }
353
+ isEditorElement(target) {
354
+ var _a;
355
+ return ((_a = this.wrapContainer) === null || _a === void 0 ? void 0 : _a.contains(target)) || this.isClickEditorElement(target);
356
+ }
357
+ isClickEditorElement(target) {
358
+ while (target) {
359
+ // 约定的类名
360
+ if (target.classList && target.classList.contains('table-editor-element')) {
361
+ return true;
362
+ }
363
+ target = target.parentNode;
364
+ }
365
+ return false;
366
+ }
329
367
  }
330
368
 
369
+ /** 动态渲染编辑器名称 */
331
370
  const DYNAMIC_RENDER_EDITOR = 'dynamic-render-editor';
332
371
 
333
- function checkRenderEditor(column, getEditCustomNode) {
334
- const { editor } = column || {};
335
- const key = getRenderEditorColumnKeyField(column);
336
- if (!vutils.isValid(key) || editor !== DYNAMIC_RENDER_EDITOR) {
337
- return false;
338
- }
339
- if (typeof getEditCustomNode === 'function') {
340
- column.getEditCustomNode = getEditCustomNode;
341
- if (Array.isArray(column.columns) && column.columns.length) {
342
- for (const childColumn of column.columns) {
343
- checkRenderEditor(childColumn, getEditCustomNode);
344
- }
345
- }
346
- return true;
347
- }
348
- return typeof column.getEditCustomNode === 'function';
349
- }
350
- function getRenderEditorColumnKeyField(column) {
351
- const { field, key } = column || {};
352
- return vutils.isValid(key) ? key : field;
353
- }
354
- function getRenderEditor(create, currentContext) {
355
- const registeredEditor = VTable.register.editor(DYNAMIC_RENDER_EDITOR);
356
- let renderEditor = registeredEditor
357
- ? registeredEditor
358
- : undefined;
359
- if (!renderEditor && !!create) {
360
- renderEditor = new DynamicRenderEditor(currentContext);
361
- VTable.register.editor(DYNAMIC_RENDER_EDITOR, renderEditor);
362
- }
363
- return renderEditor;
372
+ /**
373
+ * @description: 校验动态渲染式编辑器
374
+ * @param {any} column
375
+ * @param {any} getEditCustomNode
376
+ * @return {*}
377
+ */
378
+ function checkRenderEditor(column, getEditCustomNode) {
379
+ const { editor } = column || {};
380
+ const key = getRenderEditorColumnKeyField(column);
381
+ if (!vutils.isValid(key) || editor !== DYNAMIC_RENDER_EDITOR) {
382
+ return false;
383
+ }
384
+ if (typeof getEditCustomNode === 'function') {
385
+ column.getEditCustomNode = getEditCustomNode;
386
+ // 处理子列
387
+ if (Array.isArray(column.columns) && column.columns.length) {
388
+ for (const childColumn of column.columns) {
389
+ checkRenderEditor(childColumn, getEditCustomNode);
390
+ }
391
+ }
392
+ return true;
393
+ }
394
+ return typeof column.getEditCustomNode === 'function';
395
+ }
396
+ /**
397
+ * @description: 获取渲染式编辑器的列配置主键
398
+ * @param {any} column
399
+ * @return {*}
400
+ */
401
+ function getRenderEditorColumnKeyField(column) {
402
+ const { field, key } = column || {};
403
+ // 兼容取 field
404
+ return vutils.isValid(key) ? key : field;
405
+ }
406
+ /**
407
+ * @description: 获取动态渲染式编辑器
408
+ * @param {boolean} create
409
+ * @param {any} currentContext
410
+ * @return {*}
411
+ */
412
+ function getRenderEditor(create, currentContext) {
413
+ const registeredEditor = VTable.register.editor(DYNAMIC_RENDER_EDITOR);
414
+ let renderEditor = registeredEditor
415
+ ? registeredEditor
416
+ : undefined;
417
+ if (!renderEditor && !!create) {
418
+ // 注册自定义编辑器
419
+ renderEditor = new DynamicRenderEditor(currentContext);
420
+ VTable.register.editor(DYNAMIC_RENDER_EDITOR, renderEditor);
421
+ }
422
+ return renderEditor;
364
423
  }
365
424
 
366
- function extractPivotSlotOptions(vnodes) {
367
- const options = {
368
- columns: [],
369
- columnHeaderTitle: [],
370
- rows: [],
371
- rowHeaderTitle: [],
372
- indicators: [],
373
- corner: {},
374
- tooltip: {},
375
- menu: {}
376
- };
377
- const typeMapping = {
378
- PivotColumnDimension: 'columns',
379
- PivotColumnHeaderTitle: 'columnHeaderTitle',
380
- PivotRowDimension: 'rows',
381
- PivotRowHeaderTitle: 'rowHeaderTitle',
382
- PivotCorner: 'corner',
383
- PivotIndicator: 'indicators',
384
- Tooltip: 'tooltip',
385
- Menu: 'menu'
386
- };
387
- vnodes.forEach(vnode => {
388
- vnode.props = convertPropsToCamelCase(vnode.props);
389
- const typeName = vnode.type?.symbol || vnode.type?.name;
390
- const optionKey = typeMapping[typeName];
391
- if (optionKey) {
392
- if (Array.isArray(options[optionKey])) {
393
- if (vnode.props.hasOwnProperty('objectHandler')) {
394
- options[optionKey].push(vnode.props.objectHandler);
395
- }
396
- else {
397
- options[optionKey].push(vnode.props);
398
- }
399
- }
400
- else {
401
- options[optionKey] = vnode.props;
402
- }
403
- }
404
- });
405
- return options;
406
- }
407
- function extractListSlotOptions(vnodes) {
408
- const options = {
409
- columns: [],
410
- tooltip: {},
411
- menu: {}
412
- };
413
- const typeMapping = {
414
- ListColumn: 'columns',
415
- Tooltip: 'tooltip',
416
- Menu: 'menu'
417
- };
418
- vnodes.forEach(vnode => {
419
- vnode.props = convertPropsToCamelCase(vnode.props);
420
- const typeName = vnode.type?.symbol || vnode.type?.name;
421
- const optionKey = typeMapping[typeName];
422
- if (optionKey) {
423
- if (optionKey === 'columns' && vnode.children) {
424
- if (vnode.children.customLayout) {
425
- vnode.props.customLayout = createCustomLayoutHandler(vnode.children);
426
- }
427
- if (vnode.children.headerCustomLayout) {
428
- vnode.props.headerCustomLayout = createCustomLayoutHandler(vnode.children, true);
429
- }
430
- checkRenderEditor(vnode.props, vnode.children.edit);
431
- }
432
- if (Array.isArray(options[optionKey])) {
433
- options[optionKey].push(vnode.props);
434
- }
435
- else {
436
- options[optionKey] = vnode.props;
437
- }
438
- }
439
- });
440
- return options;
441
- }
442
- function mergeSlotOptions(propsOptions, slotOptions) {
443
- return {
444
- ...propsOptions,
445
- columns: slotOptions.columns && slotOptions.columns.length ? slotOptions.columns : propsOptions.columns,
446
- columnHeaderTitle: slotOptions.columnHeaderTitle && slotOptions.columnHeaderTitle.length
447
- ? slotOptions.columnHeaderTitle
448
- : propsOptions.columnHeaderTitle,
449
- rows: slotOptions.rows && slotOptions.rows.length ? slotOptions.rows : propsOptions.rows,
450
- rowHeaderTitle: slotOptions.rowHeaderTitle && slotOptions.rowHeaderTitle.length
451
- ? slotOptions.rowHeaderTitle
452
- : propsOptions.rowHeaderTitle,
453
- indicators: slotOptions.indicators && slotOptions.indicators.length ? slotOptions.indicators : propsOptions.indicators,
454
- corner: Object.keys(propsOptions.corner || {}).length ? propsOptions.corner : slotOptions.corner,
455
- tooltip: Object.keys(slotOptions.tooltip || {}).length ? slotOptions.tooltip : propsOptions.tooltip,
456
- menu: Object.keys(slotOptions.menu || {}).length ? slotOptions.menu : propsOptions.menu
457
- };
425
+ function extractPivotSlotOptions(vnodes) {
426
+ const options = {
427
+ columns: [],
428
+ columnHeaderTitle: [],
429
+ rows: [],
430
+ rowHeaderTitle: [],
431
+ indicators: [],
432
+ corner: {},
433
+ tooltip: {},
434
+ menu: {}
435
+ };
436
+ const typeMapping = {
437
+ PivotColumnDimension: 'columns',
438
+ PivotColumnHeaderTitle: 'columnHeaderTitle',
439
+ PivotRowDimension: 'rows',
440
+ PivotRowHeaderTitle: 'rowHeaderTitle',
441
+ PivotCorner: 'corner',
442
+ PivotIndicator: 'indicators',
443
+ Tooltip: 'tooltip',
444
+ Menu: 'menu'
445
+ };
446
+ vnodes.forEach(vnode => {
447
+ var _a, _b;
448
+ vnode.props = convertPropsToCamelCase(vnode.props);
449
+ const typeName = ((_a = vnode.type) === null || _a === void 0 ? void 0 : _a.symbol) || ((_b = vnode.type) === null || _b === void 0 ? void 0 : _b.name);
450
+ const optionKey = typeMapping[typeName];
451
+ if (optionKey) {
452
+ if (Array.isArray(options[optionKey])) {
453
+ if (vnode.props.hasOwnProperty('objectHandler')) {
454
+ options[optionKey].push(vnode.props.objectHandler);
455
+ }
456
+ else {
457
+ options[optionKey].push(vnode.props);
458
+ }
459
+ }
460
+ else {
461
+ options[optionKey] = vnode.props;
462
+ }
463
+ }
464
+ });
465
+ return options;
466
+ }
467
+ function extractListSlotOptions(vnodes) {
468
+ const options = {
469
+ columns: [],
470
+ tooltip: {},
471
+ menu: {}
472
+ };
473
+ const typeMapping = {
474
+ ListColumn: 'columns',
475
+ Tooltip: 'tooltip',
476
+ Menu: 'menu'
477
+ };
478
+ vnodes.forEach(vnode => {
479
+ var _a, _b;
480
+ vnode.props = convertPropsToCamelCase(vnode.props);
481
+ const typeName = ((_a = vnode.type) === null || _a === void 0 ? void 0 : _a.symbol) || ((_b = vnode.type) === null || _b === void 0 ? void 0 : _b.name);
482
+ const optionKey = typeMapping[typeName];
483
+ if (optionKey) {
484
+ if (optionKey === 'columns' && vnode.children) {
485
+ if (vnode.children.customLayout) {
486
+ vnode.props.customLayout = createCustomLayoutHandler(vnode.children);
487
+ }
488
+ if (vnode.children.headerCustomLayout) {
489
+ vnode.props.headerCustomLayout = createCustomLayoutHandler(vnode.children, true);
490
+ }
491
+ // 校验编辑器
492
+ checkRenderEditor(vnode.props, vnode.children.edit);
493
+ }
494
+ if (Array.isArray(options[optionKey])) {
495
+ options[optionKey].push(vnode.props);
496
+ }
497
+ else {
498
+ options[optionKey] = vnode.props;
499
+ }
500
+ }
501
+ });
502
+ return options;
503
+ }
504
+ function mergeSlotOptions(propsOptions, slotOptions) {
505
+ return Object.assign(Object.assign({}, propsOptions), { columns: slotOptions.columns && slotOptions.columns.length ? slotOptions.columns : propsOptions.columns, columnHeaderTitle: slotOptions.columnHeaderTitle && slotOptions.columnHeaderTitle.length
506
+ ? slotOptions.columnHeaderTitle
507
+ : propsOptions.columnHeaderTitle, rows: slotOptions.rows && slotOptions.rows.length ? slotOptions.rows : propsOptions.rows, rowHeaderTitle: slotOptions.rowHeaderTitle && slotOptions.rowHeaderTitle.length
508
+ ? slotOptions.rowHeaderTitle
509
+ : propsOptions.rowHeaderTitle, indicators: slotOptions.indicators && slotOptions.indicators.length ? slotOptions.indicators : propsOptions.indicators, corner: Object.keys(propsOptions.corner || {}).length ? propsOptions.corner : slotOptions.corner, tooltip: Object.keys(slotOptions.tooltip || {}).length ? slotOptions.tooltip : propsOptions.tooltip, menu: Object.keys(slotOptions.menu || {}).length ? slotOptions.menu : propsOptions.menu });
458
510
  }
459
511
 
460
- const EVENT_TYPE = {
461
- ...VTable.ListTable.EVENT_TYPE,
462
- ...VTable.PivotTable.EVENT_TYPE,
463
- ...VTable.PivotChart.EVENT_TYPE
464
- };
465
- const TABLE_EVENTS = {
466
- onClickCell: EVENT_TYPE.CLICK_CELL,
467
- onDblClickCell: EVENT_TYPE.DBLCLICK_CELL,
468
- onMouseDownCell: EVENT_TYPE.MOUSEDOWN_CELL,
469
- onMouseUpCell: EVENT_TYPE.MOUSEUP_CELL,
470
- onSelectedCell: EVENT_TYPE.SELECTED_CELL,
471
- onKeyDown: EVENT_TYPE.KEYDOWN,
472
- onMouseEnterTable: EVENT_TYPE.MOUSEENTER_TABLE,
473
- onMouseLeaveTable: EVENT_TYPE.MOUSELEAVE_TABLE,
474
- onMouseDownTable: EVENT_TYPE.MOUSEDOWN_TABLE,
475
- onMouseMoveCell: EVENT_TYPE.MOUSEMOVE_CELL,
476
- onMouseEnterCell: EVENT_TYPE.MOUSEENTER_CELL,
477
- onMouseLeaveCell: EVENT_TYPE.MOUSELEAVE_CELL,
478
- onContextMenuCell: EVENT_TYPE.CONTEXTMENU_CELL,
479
- onContextMenuCanvas: EVENT_TYPE.CONTEXTMENU_CANVAS,
480
- onResizeColumn: EVENT_TYPE.RESIZE_COLUMN,
481
- onResizeColumnEnd: EVENT_TYPE.RESIZE_COLUMN_END,
482
- onChangeHeaderPosition: EVENT_TYPE.CHANGE_HEADER_POSITION,
483
- onChangeHeaderPositionStart: EVENT_TYPE.CHANGE_HEADER_POSITION_START,
484
- onChangeHeaderPositionFail: EVENT_TYPE.CHANGE_HEADER_POSITION_FAIL,
485
- onSortClick: EVENT_TYPE.SORT_CLICK,
486
- onFreezeClick: EVENT_TYPE.FREEZE_CLICK,
487
- onScroll: EVENT_TYPE.SCROLL,
488
- onDropdownMenuClick: EVENT_TYPE.DROPDOWN_MENU_CLICK,
489
- onMouseOverChartSymbol: EVENT_TYPE.MOUSEOVER_CHART_SYMBOL,
490
- onDragSelectEnd: EVENT_TYPE.DRAG_SELECT_END,
491
- onDropdownIconClick: EVENT_TYPE.DROPDOWN_ICON_CLICK,
492
- onDropdownMenuClear: EVENT_TYPE.DROPDOWN_MENU_CLEAR,
493
- onTreeHierarchyStateChange: EVENT_TYPE.TREE_HIERARCHY_STATE_CHANGE,
494
- onShowMenu: EVENT_TYPE.SHOW_MENU,
495
- onHideMenu: EVENT_TYPE.HIDE_MENU,
496
- onIconClick: EVENT_TYPE.ICON_CLICK,
497
- onLegendItemClick: EVENT_TYPE.LEGEND_ITEM_CLICK,
498
- onLegendItemHover: EVENT_TYPE.LEGEND_ITEM_HOVER,
499
- onLegendItemUnHover: EVENT_TYPE.LEGEND_ITEM_UNHOVER,
500
- onLegendChange: EVENT_TYPE.LEGEND_CHANGE,
501
- onMouseEnterAxis: EVENT_TYPE.MOUSEENTER_AXIS,
502
- onMouseLeaveAxis: EVENT_TYPE.MOUSELEAVE_AXIS,
503
- onCheckboxStateChange: EVENT_TYPE.CHECKBOX_STATE_CHANGE,
504
- onRadioStateChange: EVENT_TYPE.RADIO_STATE_CHANGE,
505
- onAfterRender: EVENT_TYPE.AFTER_RENDER,
506
- onInitialized: EVENT_TYPE.INITIALIZED,
507
- onPivotSortClick: EVENT_TYPE.PIVOT_SORT_CLICK,
508
- onDrillMenuClick: EVENT_TYPE.DRILLMENU_CLICK,
509
- onVChartEventType: EVENT_TYPE.VCHART_EVENT_TYPE,
510
- onChangeCellValue: EVENT_TYPE.CHANGE_CELL_VALUE,
511
- onMousedownFillHandle: EVENT_TYPE.MOUSEDOWN_FILL_HANDLE,
512
- onDragFillHandleEnd: EVENT_TYPE.DRAG_FILL_HANDLE_END,
513
- onDblclickFillHandle: EVENT_TYPE.DBLCLICK_FILL_HANDLE,
514
- onScrollVerticalEnd: EVENT_TYPE.SCROLL_VERTICAL_END,
515
- onScrollHorizontalEnd: EVENT_TYPE.SCROLL_HORIZONTAL_END,
516
- onChangCellValue: EVENT_TYPE.CHANGE_CELL_VALUE,
517
- onEmptyTipClick: EVENT_TYPE.EMPTY_TIP_CLICK,
518
- onEmptyTipDblClick: EVENT_TYPE.EMPTY_TIP_DBLCLICK,
519
- onButtonClick: EVENT_TYPE.BUTTON_CLICK,
520
- onBeforeCacheChartImage: EVENT_TYPE.BEFORE_CACHE_CHART_IMAGE,
521
- onPastedData: EVENT_TYPE.PASTED_DATA,
522
- onSelectedClear: EVENT_TYPE.SELECTED_CLEAR
523
- };
512
+ const EVENT_TYPE = Object.assign(Object.assign(Object.assign({}, VTable.ListTable.EVENT_TYPE), VTable.PivotTable.EVENT_TYPE), VTable.PivotChart.EVENT_TYPE);
513
+ const TABLE_EVENTS = {
514
+ onClickCell: EVENT_TYPE.CLICK_CELL,
515
+ onDblClickCell: EVENT_TYPE.DBLCLICK_CELL,
516
+ onMouseDownCell: EVENT_TYPE.MOUSEDOWN_CELL,
517
+ onMouseUpCell: EVENT_TYPE.MOUSEUP_CELL,
518
+ onSelectedCell: EVENT_TYPE.SELECTED_CELL,
519
+ onKeyDown: EVENT_TYPE.KEYDOWN,
520
+ onMouseEnterTable: EVENT_TYPE.MOUSEENTER_TABLE,
521
+ onMouseLeaveTable: EVENT_TYPE.MOUSELEAVE_TABLE,
522
+ onMouseDownTable: EVENT_TYPE.MOUSEDOWN_TABLE,
523
+ onMouseMoveCell: EVENT_TYPE.MOUSEMOVE_CELL,
524
+ onMouseEnterCell: EVENT_TYPE.MOUSEENTER_CELL,
525
+ onMouseLeaveCell: EVENT_TYPE.MOUSELEAVE_CELL,
526
+ onContextMenuCell: EVENT_TYPE.CONTEXTMENU_CELL,
527
+ onContextMenuCanvas: EVENT_TYPE.CONTEXTMENU_CANVAS,
528
+ onResizeColumn: EVENT_TYPE.RESIZE_COLUMN,
529
+ onResizeColumnEnd: EVENT_TYPE.RESIZE_COLUMN_END,
530
+ onChangeHeaderPosition: EVENT_TYPE.CHANGE_HEADER_POSITION,
531
+ onChangeHeaderPositionStart: EVENT_TYPE.CHANGE_HEADER_POSITION_START,
532
+ onChangeHeaderPositionFail: EVENT_TYPE.CHANGE_HEADER_POSITION_FAIL,
533
+ onSortClick: EVENT_TYPE.SORT_CLICK,
534
+ onFreezeClick: EVENT_TYPE.FREEZE_CLICK,
535
+ onScroll: EVENT_TYPE.SCROLL,
536
+ onDropdownMenuClick: EVENT_TYPE.DROPDOWN_MENU_CLICK,
537
+ onMouseOverChartSymbol: EVENT_TYPE.MOUSEOVER_CHART_SYMBOL,
538
+ onDragSelectEnd: EVENT_TYPE.DRAG_SELECT_END,
539
+ onDropdownIconClick: EVENT_TYPE.DROPDOWN_ICON_CLICK,
540
+ onDropdownMenuClear: EVENT_TYPE.DROPDOWN_MENU_CLEAR,
541
+ onTreeHierarchyStateChange: EVENT_TYPE.TREE_HIERARCHY_STATE_CHANGE,
542
+ onShowMenu: EVENT_TYPE.SHOW_MENU,
543
+ onHideMenu: EVENT_TYPE.HIDE_MENU,
544
+ onIconClick: EVENT_TYPE.ICON_CLICK,
545
+ onLegendItemClick: EVENT_TYPE.LEGEND_ITEM_CLICK,
546
+ onLegendItemHover: EVENT_TYPE.LEGEND_ITEM_HOVER,
547
+ onLegendItemUnHover: EVENT_TYPE.LEGEND_ITEM_UNHOVER,
548
+ onLegendChange: EVENT_TYPE.LEGEND_CHANGE,
549
+ onMouseEnterAxis: EVENT_TYPE.MOUSEENTER_AXIS,
550
+ onMouseLeaveAxis: EVENT_TYPE.MOUSELEAVE_AXIS,
551
+ onCheckboxStateChange: EVENT_TYPE.CHECKBOX_STATE_CHANGE,
552
+ onRadioStateChange: EVENT_TYPE.RADIO_STATE_CHANGE,
553
+ onAfterRender: EVENT_TYPE.AFTER_RENDER,
554
+ onInitialized: EVENT_TYPE.INITIALIZED,
555
+ // pivot table only
556
+ onPivotSortClick: EVENT_TYPE.PIVOT_SORT_CLICK,
557
+ onDrillMenuClick: EVENT_TYPE.DRILLMENU_CLICK,
558
+ // pivot chart only
559
+ onVChartEventType: EVENT_TYPE.VCHART_EVENT_TYPE,
560
+ onChangeCellValue: EVENT_TYPE.CHANGE_CELL_VALUE,
561
+ onMousedownFillHandle: EVENT_TYPE.MOUSEDOWN_FILL_HANDLE,
562
+ onDragFillHandleEnd: EVENT_TYPE.DRAG_FILL_HANDLE_END,
563
+ onDblclickFillHandle: EVENT_TYPE.DBLCLICK_FILL_HANDLE,
564
+ onScrollVerticalEnd: EVENT_TYPE.SCROLL_VERTICAL_END,
565
+ onScrollHorizontalEnd: EVENT_TYPE.SCROLL_HORIZONTAL_END,
566
+ onChangCellValue: EVENT_TYPE.CHANGE_CELL_VALUE,
567
+ onEmptyTipClick: EVENT_TYPE.EMPTY_TIP_CLICK,
568
+ onEmptyTipDblClick: EVENT_TYPE.EMPTY_TIP_DBLCLICK,
569
+ onButtonClick: EVENT_TYPE.BUTTON_CLICK,
570
+ onBeforeCacheChartImage: EVENT_TYPE.BEFORE_CACHE_CHART_IMAGE,
571
+ onPastedData: EVENT_TYPE.PASTED_DATA,
572
+ onSelectedClear: EVENT_TYPE.SELECTED_CLEAR
573
+ };
524
574
  const TABLE_EVENTS_KEYS = Object.keys(TABLE_EVENTS);
575
+ // export const findEventProps = <T extends EventsProps>(
576
+ // props: T,
577
+ // supportedEvents: Record<string, string> = TABLE_EVENTS
578
+ // ): EventsProps => {
579
+ // const result: EventsProps = {};
580
+ // Object.keys(props).forEach(key => {
581
+ // if (supportedEvents[key] && props[key]) {
582
+ // result[key] = props[key];
583
+ // }
584
+ // });
585
+ // return result;
586
+ // };
587
+ // export const bindEventsToTable = <T>(
588
+ // table: IVTable,
589
+ // newProps?: T | null,
590
+ // prevProps?: T | null,
591
+ // supportedEvents: Record<string, string> = TABLE_EVENTS
592
+ // ) => {
593
+ // if (!table) return false;
594
+ // const prevEventProps = prevProps ? findEventProps(prevProps, supportedEvents) : {};
595
+ // const newEventProps = newProps ? findEventProps(newProps, supportedEvents) : {};
596
+ // Object.keys(supportedEvents).forEach(eventKey => {
597
+ // const prevHandler = prevEventProps[eventKey];
598
+ // const newHandler = newEventProps[eventKey];
599
+ // if (prevHandler !== newHandler) {
600
+ // if (prevHandler) {
601
+ // table.off(supportedEvents[eventKey], prevHandler);
602
+ // }
603
+ // if (newHandler) {
604
+ // table.on(supportedEvents[eventKey] as keyof TYPES.TableEventHandlersEventArgumentMap, newHandler);
605
+ // }
606
+ // }
607
+ // });
608
+ // return true;
609
+ // };
525
610
 
526
- function useEditorRender(props, tableRef) {
527
- const instance = vue.getCurrentInstance();
528
- const validColumns = vue.computed(() => {
529
- const columns = flattenColumns(props.options?.columns || []);
530
- if (!vutils.isArray(columns)) {
531
- return [];
532
- }
533
- return columns.filter(col => !!vutils.isObject(col) && !!checkRenderEditor(col));
534
- });
535
- vue.watchEffect(() => {
536
- resolveRenderEditor();
537
- });
538
- vue.onBeforeUnmount(() => {
539
- releaseRenderEditor();
540
- });
541
- function resolveRenderEditor() {
542
- const id = getTableId();
543
- if (!vutils.isValid(id)) {
544
- return;
545
- }
546
- let renderEditor = getRenderEditor();
547
- if (renderEditor) {
548
- renderEditor.removeNode(id);
549
- }
550
- else if (validColumns.value.length > 0) {
551
- renderEditor = getRenderEditor(true, instance?.appContext);
552
- }
553
- validColumns.value.forEach(column => {
554
- const { getEditCustomNode } = column;
555
- const key = getRenderEditorColumnKeyField(column);
556
- renderEditor.registerNode(id, key, getEditCustomNode);
557
- delete column.editCustomNode;
558
- });
559
- }
560
- function releaseRenderEditor() {
561
- const id = getTableId();
562
- if (!vutils.isValid(id)) {
563
- return;
564
- }
565
- const renderEditor = getRenderEditor();
566
- renderEditor?.release(id);
567
- }
568
- function getTableId() {
569
- return tableRef.value?.id;
570
- }
571
- }
572
- function flattenColumns(columns) {
573
- return columns.flatMap(column => (Array.isArray(column.columns) ? flattenColumns(column.columns) : column));
611
+ /**
612
+ * 编辑渲染器
613
+ * @param props
614
+ * @param tableRef
615
+ */
616
+ function useEditorRender(props, tableRef) {
617
+ /** 当前实例 */
618
+ const instance = vue.getCurrentInstance();
619
+ /** 需要渲染编辑器的列 */
620
+ const validColumns = vue.computed(() => {
621
+ var _a;
622
+ const columns = flattenColumns(((_a = props.options) === null || _a === void 0 ? void 0 : _a.columns) || []);
623
+ if (!vutils.isArray(columns)) {
624
+ return [];
625
+ }
626
+ return columns.filter(col => !!vutils.isObject(col) && !!checkRenderEditor(col));
627
+ });
628
+ vue.watchEffect(() => {
629
+ resolveRenderEditor();
630
+ });
631
+ vue.onBeforeUnmount(() => {
632
+ releaseRenderEditor();
633
+ });
634
+ /**
635
+ * @description: 动态渲染式编辑器
636
+ * @return {*}
637
+ */
638
+ function resolveRenderEditor() {
639
+ const id = getTableId();
640
+ if (!vutils.isValid(id)) {
641
+ return;
642
+ }
643
+ // 移除原本已存在的编辑器
644
+ let renderEditor = getRenderEditor();
645
+ if (renderEditor) {
646
+ renderEditor.removeNode(id);
647
+ }
648
+ else if (validColumns.value.length > 0) {
649
+ // 注册编辑器
650
+ renderEditor = getRenderEditor(true, instance === null || instance === void 0 ? void 0 : instance.appContext);
651
+ }
652
+ validColumns.value.forEach(column => {
653
+ const { getEditCustomNode } = column;
654
+ const key = getRenderEditorColumnKeyField(column);
655
+ renderEditor.registerNode(id, key, getEditCustomNode);
656
+ delete column.editCustomNode;
657
+ });
658
+ }
659
+ /**
660
+ * @description: 释放动态渲染式编辑器
661
+ * @return {*}
662
+ */
663
+ function releaseRenderEditor() {
664
+ const id = getTableId();
665
+ if (!vutils.isValid(id)) {
666
+ return;
667
+ }
668
+ const renderEditor = getRenderEditor();
669
+ renderEditor === null || renderEditor === void 0 ? void 0 : renderEditor.release(id);
670
+ }
671
+ /**
672
+ * @description: 获取表格 id
673
+ * @return {*}
674
+ */
675
+ function getTableId() {
676
+ var _a;
677
+ return (_a = tableRef.value) === null || _a === void 0 ? void 0 : _a.id;
678
+ }
679
+ }
680
+ /**
681
+ * @description: 获取所有扁平化的 columns
682
+ * @param {any} columns
683
+ */
684
+ function flattenColumns(columns) {
685
+ return columns.flatMap(column => (Array.isArray(column.columns) ? flattenColumns(column.columns) : column));
574
686
  }
575
687
 
576
- class VTableVueAttributePlugin extends vrender.HtmlAttributePlugin {
577
- name = 'VTableVueAttributePlugin';
578
- renderQueue = new Set();
579
- isRendering = false;
580
- MAX_CACHE_COUNT = 100;
581
- accessQueue = [];
582
- VIEWPORT_BUFFER = 100;
583
- BUFFER_ZONE = 500;
584
- styleUpdateQueue = new Map();
585
- styleUpdateRequested = false;
586
- eventHandlers = new WeakMap();
587
- currentContext;
588
- constructor(currentContext) {
589
- super();
590
- this.currentContext = currentContext;
591
- }
592
- renderGraphicHTML(graphic) {
593
- if (!this.checkNeedRender(graphic)) {
594
- return;
595
- }
596
- this.renderQueue.add(graphic);
597
- this.scheduleRender();
598
- }
599
- scheduleRender() {
600
- if (this.isRendering) {
601
- return;
602
- }
603
- this.isRendering = true;
604
- vrender.vglobal.getRequestAnimationFrame()(() => {
605
- this.renderQueue.forEach(graphic => {
606
- try {
607
- this.doRenderGraphic(graphic);
608
- }
609
- catch (error) {
610
- const { id } = this.getGraphicOptions(graphic) || {};
611
- this.removeElement(id, true);
612
- }
613
- });
614
- this.renderQueue.clear();
615
- this.isRendering = false;
616
- });
617
- }
618
- doRenderGraphic(graphic) {
619
- const { id, options } = this.getGraphicOptions(graphic);
620
- if (!id) {
621
- return;
622
- }
623
- const stage = graphic.stage;
624
- const { element, container: expectedContainer } = options;
625
- const actualContainer = expectedContainer ? checkFrozenContainer(graphic) : expectedContainer;
626
- let targetMap = this.htmlMap?.[id];
627
- if (targetMap && actualContainer && actualContainer !== targetMap.container) {
628
- this.removeElement(id);
629
- targetMap = null;
630
- }
631
- this.checkToPassAppContext(element, graphic);
632
- if (!targetMap || !this.checkDom(targetMap.wrapContainer)) {
633
- this.checkAndClearCache(graphic);
634
- const { wrapContainer, nativeContainer, reuse } = this.getWrapContainer(stage, actualContainer, { id, options });
635
- if (wrapContainer) {
636
- const dataRenderId = `${this.renderId}`;
637
- wrapContainer.id = id;
638
- wrapContainer.setAttribute('data-vue-renderId', dataRenderId);
639
- wrapContainer.style.display = 'none';
640
- if (!reuse) {
641
- vue.render(element, wrapContainer);
642
- }
643
- targetMap = {
644
- wrapContainer,
645
- nativeContainer,
646
- container: actualContainer,
647
- renderId: this.renderId,
648
- graphic,
649
- isInViewport: true,
650
- lastPosition: null,
651
- lastStyle: {}
652
- };
653
- this.htmlMap[id] = targetMap;
654
- }
655
- }
656
- if (targetMap) {
657
- targetMap.renderId = this.renderId;
658
- targetMap.lastAccessed = Date.now();
659
- this.updateAccessQueue(id);
660
- this.updateStyleOfWrapContainer(graphic, stage, targetMap.wrapContainer, targetMap.nativeContainer);
661
- }
662
- }
663
- getGraphicOptions(graphic) {
664
- const { vue } = graphic?.attribute || {};
665
- if (!vue) {
666
- return null;
667
- }
668
- const id = vutils.isNil(vue.id) ? graphic.id ?? graphic._uid : vue.id;
669
- return { id: `vue_${id}`, options: vue };
670
- }
671
- checkToPassAppContext(vnode, graphic) {
672
- try {
673
- const customConfig = this.getCustomConfig(graphic);
674
- const userAppContext = customConfig?.getVueUserAppContext?.() ?? this.currentContext;
675
- if (!!userAppContext?.components && !!userAppContext?.directives) {
676
- vnode.appContext = userAppContext;
677
- }
678
- }
679
- catch (error) { }
680
- }
681
- getCustomConfig(graphic) {
682
- const target = getTargetGroup(graphic);
683
- return target?.stage?.table?.options?.customConfig;
684
- }
685
- checkNeedRender(graphic) {
686
- const { id, options } = this.getGraphicOptions(graphic) || {};
687
- if (!id) {
688
- return false;
689
- }
690
- const stage = graphic.stage;
691
- if (!stage) {
692
- return false;
693
- }
694
- const { element } = options;
695
- if (!element) {
696
- return false;
697
- }
698
- const isInViewport = this.checkInViewport(graphic);
699
- return isInViewport;
700
- }
701
- checkInViewport(graphic) {
702
- return this.checkInViewportByZone(graphic, this.VIEWPORT_BUFFER);
703
- }
704
- checkInBuffer(graphic) {
705
- return this.checkInViewportByZone(graphic, this.BUFFER_ZONE);
706
- }
707
- checkInViewportByZone(graphic, buffer = 0) {
708
- const { stage, globalAABBBounds: cBounds } = graphic;
709
- if (!stage) {
710
- return false;
711
- }
712
- const { AABBBounds: vBounds } = stage;
713
- const eBounds = {
714
- x1: vBounds.x1 - buffer,
715
- x2: vBounds.x2 + buffer,
716
- y1: vBounds.y1 - buffer,
717
- y2: vBounds.y2 + buffer
718
- };
719
- const isIntersecting = cBounds.x1 < eBounds.x2 && cBounds.x2 > eBounds.x1 && cBounds.y1 < eBounds.y2 && cBounds.y2 > eBounds.y1;
720
- return isIntersecting;
721
- }
722
- updateAccessQueue(id) {
723
- const index = this.accessQueue.indexOf(id);
724
- if (index > -1) {
725
- this.accessQueue.splice(index, 1);
726
- }
727
- this.accessQueue.unshift(id);
728
- }
729
- checkAndClearCache(graphic) {
730
- const { viewportNodes, bufferNodes, cacheNodes } = this.classifyNodes();
731
- const total = viewportNodes.length + bufferNodes.length + cacheNodes.length;
732
- const customConfig = this.getCustomConfig(graphic);
733
- const maxTotal = customConfig?.maxDomCacheCount ?? this.MAX_CACHE_COUNT;
734
- if (total <= maxTotal) {
735
- return;
736
- }
737
- const exceedingCount = total - maxTotal;
738
- let toRemove = cacheNodes.slice(0, exceedingCount);
739
- if (toRemove.length < exceedingCount) {
740
- const bufferCandidates = bufferNodes
741
- .sort((a, b) => this.htmlMap[a].lastAccessed - this.htmlMap[b].lastAccessed)
742
- .slice(0, exceedingCount - toRemove.length);
743
- toRemove = toRemove.concat(bufferCandidates);
744
- }
745
- toRemove.forEach(id => this.removeElement(id, true));
746
- }
747
- classifyNodes() {
748
- const viewportNodes = [];
749
- const bufferNodes = [];
750
- const cacheNodes = [];
751
- Object.keys(this.htmlMap).forEach(id => {
752
- const node = this.htmlMap[id];
753
- if (node.isInViewport) {
754
- viewportNodes.push(id);
755
- }
756
- else if (this.checkInBuffer(node.graphic)) {
757
- bufferNodes.push(id);
758
- }
759
- else {
760
- cacheNodes.push(id);
761
- }
762
- });
763
- return {
764
- viewportNodes,
765
- bufferNodes,
766
- cacheNodes
767
- };
768
- }
769
- checkDom(dom) {
770
- if (!dom) {
771
- return false;
772
- }
773
- return document.contains(dom);
774
- }
775
- removeAllDom(g) {
776
- if (this.htmlMap) {
777
- Object.keys(this.htmlMap).forEach(key => {
778
- this.removeElement(key, true);
779
- });
780
- this.htmlMap = null;
781
- }
782
- }
783
- removeElement(id, clear) {
784
- const record = this.htmlMap?.[id];
785
- if (!record) {
786
- return;
787
- }
788
- const { wrapContainer } = record;
789
- if (!wrapContainer) {
790
- return;
791
- }
792
- if (!clear) {
793
- wrapContainer.remove();
794
- record.isInViewport = false;
795
- const index = this.accessQueue.indexOf(id);
796
- if (index > -1) {
797
- this.accessQueue.splice(index, 1);
798
- }
799
- }
800
- else {
801
- vue.render(null, wrapContainer);
802
- this.checkDom(wrapContainer) && super.removeElement(id);
803
- delete this.htmlMap[id];
804
- }
805
- this.removeWrapContainerEventListener(wrapContainer);
806
- }
807
- getWrapContainer(stage, userContainer, domParams) {
808
- let nativeContainer;
809
- if (userContainer) {
810
- nativeContainer =
811
- typeof userContainer === 'string' ? vrender.application.global.getElementById(userContainer) : userContainer;
812
- }
813
- else {
814
- nativeContainer = stage.window.getContainer();
815
- }
816
- const { id } = domParams || {};
817
- const record = this.htmlMap?.[id];
818
- if (record && !record.isInViewport) {
819
- const { wrapContainer } = record;
820
- if (!this.checkDom(wrapContainer)) {
821
- nativeContainer.appendChild(wrapContainer);
822
- }
823
- return {
824
- reuse: true,
825
- wrapContainer,
826
- nativeContainer
827
- };
828
- }
829
- return {
830
- wrapContainer: vrender.application.global.createDom({ tagName: 'div', parent: nativeContainer }),
831
- nativeContainer
832
- };
833
- }
834
- updateStyleOfWrapContainer(graphic, stage, wrapContainer, nativeContainer) {
835
- const { attribute, type } = graphic;
836
- const { vue: options, width, height, visible, display, ...rest } = attribute || {};
837
- const { x: left, y: top } = this.calculatePosition(graphic, options.anchorType);
838
- const { left: offsetX, top: offsetTop } = this.calculateOffset(stage, nativeContainer, left, top);
839
- const { id } = this.getGraphicOptions(graphic) || {};
840
- const record = id ? this.htmlMap[id] : null;
841
- if (!record) {
842
- return;
843
- }
844
- const positionChanged = !record.lastPosition || record.lastPosition.x !== offsetX || record.lastPosition.y !== offsetTop;
845
- if (!positionChanged) {
846
- return;
847
- }
848
- const { pointerEvents } = options;
849
- const calculateStyle = this.parseDefaultStyleFromGraphic(graphic);
850
- const style = this.convertCellStyle(graphic);
851
- Object.assign(calculateStyle, {
852
- width: `${width}px`,
853
- height: `${height}px`,
854
- overflow: 'hidden',
855
- ...(style || {}),
856
- ...(rest || {}),
857
- transform: `translate(${offsetX}px, ${offsetTop}px)`,
858
- boxSizing: 'border-box',
859
- display: visible !== false ? display || 'block' : 'none',
860
- pointerEvents: pointerEvents === true ? 'all' : pointerEvents || 'none',
861
- position: 'absolute'
862
- });
863
- if (calculateStyle.pointerEvents !== 'none') {
864
- this.checkToAddEventListener(wrapContainer);
865
- }
866
- if (type === 'text' && options.anchorType === 'position') {
867
- Object.assign(calculateStyle, this.getTransformOfText(graphic));
868
- }
869
- this.applyUserStyles(options, calculateStyle, { offsetX, offsetTop, graphic, wrapContainer });
870
- const styleChanged = !vutils.isEqual(record.lastStyle, calculateStyle);
871
- if (styleChanged) {
872
- this.styleUpdateQueue.set(wrapContainer.id, calculateStyle);
873
- this.requestStyleUpdate();
874
- record.lastStyle = calculateStyle;
875
- }
876
- }
877
- checkToAddEventListener(wrapContainer) {
878
- if (!this.eventHandlers.has(wrapContainer)) {
879
- const handler = (e) => {
880
- e.preventDefault();
881
- this.onWheel(e);
882
- };
883
- wrapContainer.addEventListener('wheel', handler, { passive: false });
884
- this.eventHandlers.set(wrapContainer, handler);
885
- }
886
- }
887
- requestStyleUpdate() {
888
- if (!this.styleUpdateRequested) {
889
- this.styleUpdateRequested = true;
890
- vrender.vglobal.getRequestAnimationFrame()(() => {
891
- this.styleUpdateQueue.forEach((changes, id) => {
892
- const container = this.htmlMap?.[id]?.wrapContainer;
893
- if (container) {
894
- Object.assign(container.style, changes);
895
- }
896
- });
897
- this.styleUpdateQueue.clear();
898
- this.styleUpdateRequested = false;
899
- });
900
- }
901
- }
902
- convertCellStyle(graphic) {
903
- const { col, row, stage } = getTargetGroup(graphic);
904
- const style = stage?.table?.getCellStyle(col, row);
905
- if (!vutils.isObject(style)) {
906
- return;
907
- }
908
- const { lineHeight, padding, ...rest } = style;
909
- return {
910
- ...rest,
911
- padding: vutils.isArray(padding) ? padding.map(value => `${value}px`).join(' ') : padding
912
- };
913
- }
914
- calculatePosition(graphic, anchorType) {
915
- const bounds = graphic.globalAABBBounds;
916
- if (anchorType === 'position' || bounds.empty()) {
917
- const matrix = graphic.globalTransMatrix;
918
- return { x: matrix.e, y: matrix.f };
919
- }
920
- return vutils.calculateAnchorOfBounds(bounds, anchorType || 'top-left');
921
- }
922
- calculateOffset(stage, nativeContainer, x, y) {
923
- const containerTL = vrender.application.global.getElementTopLeft(nativeContainer, false);
924
- const windowTL = stage.window.getTopLeft(false);
925
- return {
926
- left: x + windowTL.left - containerTL.left,
927
- top: y + windowTL.top - containerTL.top
928
- };
929
- }
930
- applyUserStyles(options, baseStyle, context) {
931
- if (vutils.isFunction(options.style)) {
932
- const userStyle = options.style({
933
- top: context.offsetTop,
934
- left: context.offsetX,
935
- width: context.graphic.globalAABBBounds.width(),
936
- height: context.graphic.globalAABBBounds.height()
937
- }, context.graphic, context.wrapContainer);
938
- Object.assign(baseStyle, userStyle);
939
- }
940
- else if (vutils.isObject(options.style)) {
941
- Object.assign(baseStyle, options.style);
942
- }
943
- else if (vutils.isString(options.style)) {
944
- Object.assign(baseStyle, vutils.styleStringToObject(options.style));
945
- }
946
- }
947
- }
948
- function checkFrozenContainer(graphic) {
949
- const { col, row, stage } = getTargetGroup(graphic);
950
- let container = graphic.attribute.vue?.container;
951
- const { table } = stage;
952
- if (container === table.bodyDomContainer) {
953
- if (col < table.frozenColCount && row >= table.rowCount - table.bottomFrozenRowCount) {
954
- container = table.bottomFrozenBodyDomContainer;
955
- }
956
- else if (col >= table.colCount - table.rightFrozenColCount &&
957
- row >= table.rowCount - table.bottomFrozenRowCount) {
958
- container = table.rightFrozenBottomDomContainer;
959
- }
960
- else if (row >= table.rowCount - table.bottomFrozenRowCount) {
961
- container = table.bottomFrozenBodyDomContainer;
962
- }
963
- else if (col < table.frozenColCount) {
964
- container = table.frozenBodyDomContainer;
965
- }
966
- else if (col >= table.colCount - table.rightFrozenColCount) {
967
- container = table.rightFrozenBodyDomContainer;
968
- }
969
- }
970
- else if (container === table.headerDomContainer) {
971
- if (col < table.frozenColCount) {
972
- container = table.frozenHeaderDomContainer;
973
- }
974
- else if (col >= table.colCount - table.rightFrozenColCount) {
975
- container = table.rightFrozenHeaderDomContainer;
976
- }
977
- }
978
- return container;
979
- }
980
- function getTargetGroup(target) {
981
- while (target?.parent) {
982
- if (target.name === VTable.CUSTOM_CONTAINER_NAME || (target.name || '').startsWith(VTable.CUSTOM_MERGE_PRE_NAME)) {
983
- return target;
984
- }
985
- target = target.parent;
986
- }
987
- return { col: -1, row: -1, stage: null };
688
+ var __rest = (undefined && undefined.__rest) || function (s, e) {
689
+ var t = {};
690
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
691
+ t[p] = s[p];
692
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
693
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
694
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
695
+ t[p[i]] = s[p[i]];
696
+ }
697
+ return t;
698
+ };
699
+ /**
700
+ * 表格自定义组件集成插件
701
+ */
702
+ class VTableVueAttributePlugin extends vrender.HtmlAttributePlugin {
703
+ constructor(currentContext) {
704
+ super();
705
+ this.name = 'VTableVueAttributePlugin';
706
+ /** 渲染队列 */
707
+ this.renderQueue = new Set();
708
+ /** 是否正在渲染 */
709
+ this.isRendering = false;
710
+ /** 最大缓存节点数(兜底值) */
711
+ this.MAX_CACHE_COUNT = 100;
712
+ /** 记录节点访问顺序(LRU用) */
713
+ this.accessQueue = [];
714
+ /** 目标可视区区(可视区外一定范围内的节点,保留) */
715
+ this.VIEWPORT_BUFFER = 100;
716
+ /** 缓冲区(非可视区且非缓冲区的节点需清理) */
717
+ this.BUFFER_ZONE = 500;
718
+ // 新增批量更新队列
719
+ this.styleUpdateQueue = new Map();
720
+ /** 样式更新中 */
721
+ this.styleUpdateRequested = false;
722
+ /** 事件集 */
723
+ this.eventHandlers = new WeakMap();
724
+ this.currentContext = currentContext;
725
+ }
726
+ /**
727
+ * @description: 单元格变化后重新渲染组件,由 HtmlAttributePlugin 插件触发
728
+ * @param {IGraphic} graphic
729
+ * @return {*}
730
+ */
731
+ renderGraphicHTML(graphic) {
732
+ if (!this.checkNeedRender(graphic)) {
733
+ return;
734
+ }
735
+ // 加入异步渲染队列
736
+ this.renderQueue.add(graphic);
737
+ this.scheduleRender();
738
+ }
739
+ /**
740
+ * @description: 渲染调度
741
+ * @return {*}
742
+ */
743
+ scheduleRender() {
744
+ if (this.isRendering) {
745
+ return;
746
+ }
747
+ this.isRendering = true;
748
+ vrender.vglobal.getRequestAnimationFrame()(() => {
749
+ this.renderQueue.forEach(graphic => {
750
+ try {
751
+ this.doRenderGraphic(graphic);
752
+ }
753
+ catch (error) {
754
+ const { id } = this.getGraphicOptions(graphic) || {};
755
+ this.removeElement(id, true);
756
+ }
757
+ });
758
+ this.renderQueue.clear();
759
+ this.isRendering = false;
760
+ });
761
+ }
762
+ /**
763
+ * @description: 单元格变化后实际组件渲染方法
764
+ * @param {IGraphic} graphic
765
+ * @return {*}
766
+ */
767
+ doRenderGraphic(graphic) {
768
+ var _a;
769
+ const { id, options } = this.getGraphicOptions(graphic);
770
+ if (!id) {
771
+ return;
772
+ }
773
+ const stage = graphic.stage;
774
+ const { element, container: expectedContainer } = options;
775
+ // 获取实际容器
776
+ const actualContainer = expectedContainer ? checkFrozenContainer(graphic) : expectedContainer;
777
+ // 检查是否需要移除旧容器
778
+ let targetMap = (_a = this.htmlMap) === null || _a === void 0 ? void 0 : _a[id];
779
+ if (targetMap && actualContainer && actualContainer !== targetMap.container) {
780
+ // 容器变更
781
+ this.removeElement(id);
782
+ targetMap = null;
783
+ }
784
+ // 校验并传递上下文
785
+ this.checkToPassAppContext(element, graphic);
786
+ // 渲染或更新 Vue 组件
787
+ if (!targetMap || !this.checkDom(targetMap.wrapContainer)) {
788
+ // 缓存节点检查
789
+ this.checkAndClearCache(graphic);
790
+ const { wrapContainer, nativeContainer, reuse } = this.getWrapContainer(stage, actualContainer, { id, options });
791
+ if (wrapContainer) {
792
+ const dataRenderId = `${this.renderId}`;
793
+ wrapContainer.id = id;
794
+ wrapContainer.setAttribute('data-vue-renderId', dataRenderId);
795
+ // 先隐藏
796
+ wrapContainer.style.display = 'none';
797
+ if (!reuse) {
798
+ // 仅在非复用时需要重新渲染
799
+ vue.render(element, wrapContainer);
800
+ }
801
+ targetMap = {
802
+ wrapContainer,
803
+ nativeContainer,
804
+ container: actualContainer,
805
+ renderId: this.renderId,
806
+ graphic,
807
+ isInViewport: true,
808
+ lastPosition: null,
809
+ lastStyle: {}
810
+ };
811
+ this.htmlMap[id] = targetMap;
812
+ }
813
+ }
814
+ // 更新样式并记录渲染 ID
815
+ if (targetMap) {
816
+ targetMap.renderId = this.renderId;
817
+ targetMap.lastAccessed = Date.now();
818
+ this.updateAccessQueue(id);
819
+ this.updateStyleOfWrapContainer(graphic, stage, targetMap.wrapContainer, targetMap.nativeContainer);
820
+ }
821
+ }
822
+ /**
823
+ * @description: 获取渲染参数
824
+ * @param {IGraphic} graphic
825
+ * @return {*}
826
+ */
827
+ getGraphicOptions(graphic) {
828
+ var _a;
829
+ // TODO render 组件接入 vue 类型
830
+ //@ts-ignore
831
+ const { vue } = (graphic === null || graphic === void 0 ? void 0 : graphic.attribute) || {};
832
+ if (!vue) {
833
+ return null;
834
+ }
835
+ const id = vutils.isNil(vue.id) ? (_a = graphic.id) !== null && _a !== void 0 ? _a : graphic._uid : vue.id;
836
+ return { id: `vue_${id}`, options: vue };
837
+ }
838
+ /**
839
+ * @description: 校验并传递上下文
840
+ * @param {VNode} vnode
841
+ * @param {IGraphic} graphic
842
+ * @return {*}
843
+ */
844
+ checkToPassAppContext(vnode, graphic) {
845
+ var _a, _b;
846
+ try {
847
+ const customConfig = this.getCustomConfig(graphic);
848
+ const userAppContext = (_b = (_a = customConfig === null || customConfig === void 0 ? void 0 : customConfig.getVueUserAppContext) === null || _a === void 0 ? void 0 : _a.call(customConfig)) !== null && _b !== void 0 ? _b : this.currentContext;
849
+ // 简单校验合法性
850
+ if (!!(userAppContext === null || userAppContext === void 0 ? void 0 : userAppContext.components) && !!(userAppContext === null || userAppContext === void 0 ? void 0 : userAppContext.directives)) {
851
+ vnode.appContext = userAppContext;
852
+ }
853
+ }
854
+ catch (error) { }
855
+ }
856
+ /**
857
+ * @description: 获取自定义配置
858
+ * @param {IGraphic} graphic
859
+ * @return {*}
860
+ */
861
+ getCustomConfig(graphic) {
862
+ var _a, _b, _c;
863
+ const target = getTargetGroup(graphic);
864
+ return (_c = (_b = (_a = target === null || target === void 0 ? void 0 : target.stage) === null || _a === void 0 ? void 0 : _a.table) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.customConfig;
865
+ }
866
+ /**
867
+ * @description: 检查是否需要渲染
868
+ * @param {IGraphic} graphic
869
+ * @return {*}
870
+ */
871
+ checkNeedRender(graphic) {
872
+ const { id, options } = this.getGraphicOptions(graphic) || {};
873
+ if (!id) {
874
+ return false;
875
+ }
876
+ const stage = graphic.stage;
877
+ if (!stage) {
878
+ return false;
879
+ }
880
+ const { element } = options;
881
+ if (!element) {
882
+ return false;
883
+ }
884
+ const isInViewport = this.checkInViewport(graphic);
885
+ // 不在可视区内暂时不需要移除,因为在 clearCacheContainer 方法中提前被移除了
886
+ return isInViewport;
887
+ }
888
+ /**
889
+ * @description: 判断是否在可视范围内
890
+ * @param {IGraphic} graphic
891
+ * @return {*}
892
+ */
893
+ checkInViewport(graphic) {
894
+ return this.checkInViewportByZone(graphic, this.VIEWPORT_BUFFER);
895
+ }
896
+ /**
897
+ * @description: 判断是否在缓冲区内
898
+ * @param {IGraphic} graphic
899
+ * @return {*}
900
+ */
901
+ checkInBuffer(graphic) {
902
+ return this.checkInViewportByZone(graphic, this.BUFFER_ZONE);
903
+ }
904
+ /**
905
+ * @description: 判断当前是否在指定视口范围内
906
+ * @param {IGraphic} graphic
907
+ * @param {number} buffer
908
+ * @return {*}
909
+ */
910
+ checkInViewportByZone(graphic, buffer = 0) {
911
+ const { stage, globalAABBBounds: cBounds } = graphic;
912
+ if (!stage) {
913
+ return false;
914
+ }
915
+ // 获取视口的AABB边界
916
+ //@ts-ignore
917
+ const { AABBBounds: vBounds } = stage;
918
+ // 扩展视口判断范围
919
+ const eBounds = {
920
+ x1: vBounds.x1 - buffer,
921
+ x2: vBounds.x2 + buffer,
922
+ y1: vBounds.y1 - buffer,
923
+ y2: vBounds.y2 + buffer
924
+ };
925
+ // 判断两个区域是否相交
926
+ const isIntersecting = cBounds.x1 < eBounds.x2 && cBounds.x2 > eBounds.x1 && cBounds.y1 < eBounds.y2 && cBounds.y2 > eBounds.y1;
927
+ return isIntersecting;
928
+ }
929
+ /**
930
+ * @description: 节点访问顺序队列
931
+ * @param {string} id
932
+ * @return {*}
933
+ */
934
+ updateAccessQueue(id) {
935
+ // 移除旧记录
936
+ const index = this.accessQueue.indexOf(id);
937
+ if (index > -1) {
938
+ this.accessQueue.splice(index, 1);
939
+ }
940
+ // 添加到队列头部
941
+ this.accessQueue.unshift(id);
942
+ }
943
+ /**
944
+ * @description: 在添加新节点前检查缓存大小
945
+ * @param {IGraphic} graphic
946
+ * @return {*}
947
+ */
948
+ checkAndClearCache(graphic) {
949
+ var _a;
950
+ const { viewportNodes, bufferNodes, cacheNodes } = this.classifyNodes();
951
+ const total = viewportNodes.length + bufferNodes.length + cacheNodes.length;
952
+ const customConfig = this.getCustomConfig(graphic);
953
+ const maxTotal = (_a = customConfig === null || customConfig === void 0 ? void 0 : customConfig.maxDomCacheCount) !== null && _a !== void 0 ? _a : this.MAX_CACHE_COUNT;
954
+ // 仅当总数超过阈值时清理
955
+ if (total <= maxTotal) {
956
+ return;
957
+ }
958
+ const exceedingCount = total - maxTotal;
959
+ // 优先清理缓存区节点: 移除缓存区的前 exceedingCount 个节点
960
+ let toRemove = cacheNodes.slice(0, exceedingCount);
961
+ // 若缓存区节点不满足阈值,为了控制内存占用率,按最后访问时间清除最早访问的缓冲区节点
962
+ if (toRemove.length < exceedingCount) {
963
+ const bufferCandidates = bufferNodes
964
+ .sort((a, b) => this.htmlMap[a].lastAccessed - this.htmlMap[b].lastAccessed)
965
+ .slice(0, exceedingCount - toRemove.length);
966
+ toRemove = toRemove.concat(bufferCandidates);
967
+ }
968
+ // 执行清理
969
+ toRemove.forEach(id => this.removeElement(id, true));
970
+ }
971
+ /**
972
+ * @description: 节点按可视区/缓存区/缓冲区分类
973
+ * @return {*}
974
+ */
975
+ classifyNodes() {
976
+ /** 可视区节点 */
977
+ const viewportNodes = [];
978
+ /** 缓冲区节点 */
979
+ const bufferNodes = [];
980
+ /** 既不在可视区也不在缓冲区的节点 */
981
+ const cacheNodes = [];
982
+ Object.keys(this.htmlMap).forEach(id => {
983
+ const node = this.htmlMap[id];
984
+ if (node.isInViewport) {
985
+ viewportNodes.push(id);
986
+ }
987
+ else if (this.checkInBuffer(node.graphic)) {
988
+ bufferNodes.push(id);
989
+ }
990
+ else {
991
+ cacheNodes.push(id);
992
+ }
993
+ });
994
+ return {
995
+ viewportNodes,
996
+ bufferNodes,
997
+ cacheNodes
998
+ };
999
+ }
1000
+ /**
1001
+ * @description: 检查 dom 是否存在
1002
+ * @param {HTMLElement} dom
1003
+ * @return {*}
1004
+ */
1005
+ checkDom(dom) {
1006
+ if (!dom) {
1007
+ return false;
1008
+ }
1009
+ return document.contains(dom);
1010
+ }
1011
+ /**
1012
+ * @description: 清除所有 dom
1013
+ * @param {IGraphic} g
1014
+ * @return {*}
1015
+ */
1016
+ removeAllDom(g) {
1017
+ if (this.htmlMap) {
1018
+ Object.keys(this.htmlMap).forEach(key => {
1019
+ this.removeElement(key, true);
1020
+ });
1021
+ this.htmlMap = null;
1022
+ }
1023
+ }
1024
+ /**
1025
+ * @description: 移除元素
1026
+ * @param {string} id
1027
+ * @param {boolean} clear 强制清除
1028
+ * @return {*}
1029
+ * 目前涉及到页面重绘的操作(比如列宽拖动会使得图形重绘,id变更),会有短暂的容器插拔现象
1030
+ */
1031
+ removeElement(id, clear) {
1032
+ var _a;
1033
+ const record = (_a = this.htmlMap) === null || _a === void 0 ? void 0 : _a[id];
1034
+ if (!record) {
1035
+ return;
1036
+ }
1037
+ const { wrapContainer } = record;
1038
+ if (!wrapContainer) {
1039
+ return;
1040
+ }
1041
+ if (!clear) {
1042
+ // 移除 dom 但保留在 htmlMap 中,供下次进入可视区时快速复用
1043
+ wrapContainer.remove();
1044
+ // 标记不在视口
1045
+ record.isInViewport = false;
1046
+ // 清理访问队列
1047
+ const index = this.accessQueue.indexOf(id);
1048
+ if (index > -1) {
1049
+ this.accessQueue.splice(index, 1);
1050
+ }
1051
+ }
1052
+ else {
1053
+ // 卸载子组件
1054
+ vue.render(null, wrapContainer);
1055
+ this.checkDom(wrapContainer) && super.removeElement(id);
1056
+ // 清理引用
1057
+ delete this.htmlMap[id];
1058
+ }
1059
+ // 清理事件
1060
+ this.removeWrapContainerEventListener(wrapContainer);
1061
+ }
1062
+ /**
1063
+ * @description: 获取包裹容器
1064
+ * @param {IStage} stage
1065
+ * @param {string} userContainer
1066
+ * @param {CreateDOMParamsType} domParams
1067
+ * @return {*}
1068
+ */
1069
+ getWrapContainer(stage, userContainer, domParams) {
1070
+ var _a;
1071
+ let nativeContainer;
1072
+ if (userContainer) {
1073
+ nativeContainer =
1074
+ typeof userContainer === 'string' ? vrender.application.global.getElementById(userContainer) : userContainer;
1075
+ }
1076
+ else {
1077
+ nativeContainer = stage.window.getContainer();
1078
+ }
1079
+ const { id } = domParams || {};
1080
+ // 从 htmlMap 查找可复用 dom
1081
+ const record = (_a = this.htmlMap) === null || _a === void 0 ? void 0 : _a[id];
1082
+ if (record && !record.isInViewport) {
1083
+ const { wrapContainer } = record;
1084
+ if (!this.checkDom(wrapContainer)) {
1085
+ // 添加游离节点
1086
+ nativeContainer.appendChild(wrapContainer);
1087
+ }
1088
+ return {
1089
+ reuse: true,
1090
+ wrapContainer,
1091
+ nativeContainer
1092
+ };
1093
+ }
1094
+ return {
1095
+ wrapContainer: vrender.application.global.createDom({ tagName: 'div', parent: nativeContainer }),
1096
+ nativeContainer
1097
+ };
1098
+ }
1099
+ /**
1100
+ * @description: 更新包裹容器样式
1101
+ * @param {IGraphic} graphic
1102
+ * @param {IStage} stage
1103
+ * @param {HTMLElement} wrapContainer
1104
+ * @param {HTMLElement} nativeContainer
1105
+ * @return {*}
1106
+ */
1107
+ updateStyleOfWrapContainer(graphic, stage, wrapContainer, nativeContainer) {
1108
+ const { attribute, type } = graphic;
1109
+ //@ts-ignore
1110
+ const _a = attribute || {}, { vue: options, width, height, visible, display } = _a, rest = __rest(_a, ["vue", "width", "height", "visible", "display"]);
1111
+ const { x: left, y: top } = this.calculatePosition(graphic, options.anchorType);
1112
+ const { left: offsetX, top: offsetTop } = this.calculateOffset(stage, nativeContainer, left, top);
1113
+ const { id } = this.getGraphicOptions(graphic) || {};
1114
+ const record = id ? this.htmlMap[id] : null;
1115
+ if (!record) {
1116
+ return;
1117
+ }
1118
+ // 位置变化检查
1119
+ const positionChanged = !record.lastPosition || record.lastPosition.x !== offsetX || record.lastPosition.y !== offsetTop;
1120
+ if (!positionChanged) {
1121
+ // 位置没有变化,无需更新样式
1122
+ return;
1123
+ }
1124
+ // 默认自定义区域内也可带动表格画布滚动
1125
+ const { pointerEvents } = options;
1126
+ const calculateStyle = this.parseDefaultStyleFromGraphic(graphic);
1127
+ // 单元格样式
1128
+ const style = this.convertCellStyle(graphic);
1129
+ Object.assign(calculateStyle, Object.assign(Object.assign(Object.assign({ width: `${width}px`, height: `${height}px`, overflow: 'hidden' }, (style || {})), (rest || {})), { transform: `translate(${offsetX}px, ${offsetTop}px)`, boxSizing: 'border-box', display: visible !== false ? display || 'block' : 'none', pointerEvents: pointerEvents === true ? 'all' : pointerEvents || 'none', position: 'absolute' }));
1130
+ if (calculateStyle.pointerEvents !== 'none') {
1131
+ this.checkToAddEventListener(wrapContainer);
1132
+ }
1133
+ if (type === 'text' && options.anchorType === 'position') {
1134
+ Object.assign(calculateStyle, this.getTransformOfText(graphic));
1135
+ }
1136
+ this.applyUserStyles(options, calculateStyle, { offsetX, offsetTop, graphic, wrapContainer });
1137
+ // 样式变化检查
1138
+ const styleChanged = !vutils.isEqual(record.lastStyle, calculateStyle);
1139
+ if (styleChanged) {
1140
+ this.styleUpdateQueue.set(wrapContainer.id, calculateStyle);
1141
+ // 请求批量更新
1142
+ this.requestStyleUpdate();
1143
+ // TODO 确认是否需要对接 VTableBrowserEnvContribution
1144
+ // application.global.updateDom(wrapContainer, {
1145
+ // width,
1146
+ // height,
1147
+ // style: calculateStyle
1148
+ // });
1149
+ record.lastStyle = calculateStyle;
1150
+ }
1151
+ }
1152
+ /**
1153
+ * @description: 事件监听器管理
1154
+ * @param {HTMLElement} wrapContainer
1155
+ * @return {*}
1156
+ */
1157
+ checkToAddEventListener(wrapContainer) {
1158
+ if (!this.eventHandlers.has(wrapContainer)) {
1159
+ const handler = (e) => {
1160
+ e.preventDefault();
1161
+ this.onWheel(e);
1162
+ };
1163
+ wrapContainer.addEventListener('wheel', handler, { passive: false });
1164
+ this.eventHandlers.set(wrapContainer, handler);
1165
+ }
1166
+ }
1167
+ /**
1168
+ * @description: 样式更新
1169
+ * @return {*}
1170
+ */
1171
+ requestStyleUpdate() {
1172
+ if (!this.styleUpdateRequested) {
1173
+ this.styleUpdateRequested = true;
1174
+ vrender.vglobal.getRequestAnimationFrame()(() => {
1175
+ this.styleUpdateQueue.forEach((changes, id) => {
1176
+ var _a, _b;
1177
+ const container = (_b = (_a = this.htmlMap) === null || _a === void 0 ? void 0 : _a[id]) === null || _b === void 0 ? void 0 : _b.wrapContainer;
1178
+ if (container) {
1179
+ Object.assign(container.style, changes);
1180
+ }
1181
+ });
1182
+ this.styleUpdateQueue.clear();
1183
+ this.styleUpdateRequested = false;
1184
+ });
1185
+ }
1186
+ }
1187
+ /**
1188
+ * @description: 转换单元格样式
1189
+ * @param {IGraphic} graphic
1190
+ * @return {*}
1191
+ */
1192
+ convertCellStyle(graphic) {
1193
+ var _a;
1194
+ const { col, row, stage } = getTargetGroup(graphic);
1195
+ const style = (_a = stage === null || stage === void 0 ? void 0 : stage.table) === null || _a === void 0 ? void 0 : _a.getCellStyle(col, row);
1196
+ if (!vutils.isObject(style)) {
1197
+ return;
1198
+ }
1199
+ const _b = style, { lineHeight, padding } = _b, rest = __rest(_b, ["lineHeight", "padding"]);
1200
+ // TODO 表格提供具体解析方法,暂时只解析padding
1201
+ return Object.assign(Object.assign({}, rest), { padding: vutils.isArray(padding) ? padding.map(value => `${value}px`).join(' ') : padding });
1202
+ }
1203
+ /**
1204
+ * @description: 位置计算
1205
+ * @param {IGraphic} graphic
1206
+ * @param {string} anchorType
1207
+ * @return {*}
1208
+ */
1209
+ calculatePosition(graphic, anchorType) {
1210
+ const bounds = graphic.globalAABBBounds;
1211
+ if (anchorType === 'position' || bounds.empty()) {
1212
+ const matrix = graphic.globalTransMatrix;
1213
+ return { x: matrix.e, y: matrix.f };
1214
+ }
1215
+ return vutils.calculateAnchorOfBounds(bounds, anchorType || 'top-left');
1216
+ }
1217
+ /**
1218
+ * @description: 偏移计算
1219
+ * @param {IStage} stage
1220
+ * @param {HTMLElement} nativeContainer
1221
+ * @param {number} x
1222
+ * @param {number} y
1223
+ * @return {*}
1224
+ */
1225
+ calculateOffset(stage, nativeContainer, x, y) {
1226
+ const containerTL = vrender.application.global.getElementTopLeft(nativeContainer, false);
1227
+ const windowTL = stage.window.getTopLeft(false);
1228
+ return {
1229
+ left: x + windowTL.left - containerTL.left,
1230
+ top: y + windowTL.top - containerTL.top
1231
+ };
1232
+ }
1233
+ /**
1234
+ * @description: 应用用户样式
1235
+ * @param {SimpleDomStyleOptions & CommonDomOptions} options
1236
+ * @param {Record<string, any>} baseStyle
1237
+ * @param {Object} context
1238
+ * @return {*}
1239
+ */
1240
+ applyUserStyles(options, baseStyle, context) {
1241
+ if (vutils.isFunction(options.style)) {
1242
+ const userStyle = options.style({
1243
+ top: context.offsetTop,
1244
+ left: context.offsetX,
1245
+ width: context.graphic.globalAABBBounds.width(),
1246
+ height: context.graphic.globalAABBBounds.height()
1247
+ }, context.graphic, context.wrapContainer);
1248
+ Object.assign(baseStyle, userStyle);
1249
+ }
1250
+ else if (vutils.isObject(options.style)) {
1251
+ Object.assign(baseStyle, options.style);
1252
+ }
1253
+ else if (vutils.isString(options.style)) {
1254
+ Object.assign(baseStyle, vutils.styleStringToObject(options.style));
1255
+ }
1256
+ }
1257
+ }
1258
+ /**
1259
+ * @description: 检查冻结容器
1260
+ * @param {IGraphic} graphic
1261
+ * @return {*}
1262
+ */
1263
+ function checkFrozenContainer(graphic) {
1264
+ var _a;
1265
+ const { col, row, stage } = getTargetGroup(graphic);
1266
+ // @ts-ignore
1267
+ let container = (_a = graphic.attribute.vue) === null || _a === void 0 ? void 0 : _a.container;
1268
+ const { table } = stage;
1269
+ if (container === table.bodyDomContainer) {
1270
+ if (col < table.frozenColCount && row >= table.rowCount - table.bottomFrozenRowCount) {
1271
+ container = table.bottomFrozenBodyDomContainer;
1272
+ }
1273
+ else if (col >= table.colCount - table.rightFrozenColCount &&
1274
+ row >= table.rowCount - table.bottomFrozenRowCount) {
1275
+ container = table.rightFrozenBottomDomContainer;
1276
+ }
1277
+ else if (row >= table.rowCount - table.bottomFrozenRowCount) {
1278
+ container = table.bottomFrozenBodyDomContainer;
1279
+ }
1280
+ else if (col < table.frozenColCount) {
1281
+ container = table.frozenBodyDomContainer;
1282
+ }
1283
+ else if (col >= table.colCount - table.rightFrozenColCount) {
1284
+ container = table.rightFrozenBodyDomContainer;
1285
+ }
1286
+ }
1287
+ else if (container === table.headerDomContainer) {
1288
+ if (col < table.frozenColCount) {
1289
+ container = table.frozenHeaderDomContainer;
1290
+ }
1291
+ else if (col >= table.colCount - table.rightFrozenColCount) {
1292
+ container = table.rightFrozenHeaderDomContainer;
1293
+ }
1294
+ }
1295
+ return container;
1296
+ }
1297
+ /**
1298
+ * @description: 获取目标组
1299
+ * @param {any} target
1300
+ * @return {*}
1301
+ */
1302
+ function getTargetGroup(target) {
1303
+ while (target === null || target === void 0 ? void 0 : target.parent) {
1304
+ if (target.name === VTable.CUSTOM_CONTAINER_NAME || (target.name || '').startsWith(VTable.CUSTOM_MERGE_PRE_NAME)) {
1305
+ return target;
1306
+ }
1307
+ target = target.parent;
1308
+ }
1309
+ return { col: -1, row: -1, stage: null };
988
1310
  }
989
1311
 
990
- function useCellRender(props, tableRef) {
991
- const instance = vue.getCurrentInstance();
992
- const createReactContainer = props?.options?.customConfig?.createReactContainer;
993
- vue.watchEffect(() => {
994
- if (!createReactContainer) {
995
- return;
996
- }
997
- const pluginService = tableRef.value?.scenegraph?.stage?.pluginService;
998
- if (!pluginService) {
999
- return;
1000
- }
1001
- const exist = pluginService.findPluginsByName('VTableVueAttributePlugin');
1002
- if (vutils.isArray(exist) && !!exist.length) {
1003
- return;
1004
- }
1005
- const plugin = new VTableVueAttributePlugin(instance?.appContext);
1006
- pluginService.register(plugin);
1007
- });
1312
+ /**
1313
+ * 自定义单元格渲染器
1314
+ * @param props
1315
+ * @param tableRef
1316
+ */
1317
+ function useCellRender(props, tableRef) {
1318
+ var _a, _b;
1319
+ /** 当前实例 */
1320
+ const instance = vue.getCurrentInstance();
1321
+ /** 自定义 dom 开关 */
1322
+ const createReactContainer = (_b = (_a = props === null || props === void 0 ? void 0 : props.options) === null || _a === void 0 ? void 0 : _a.customConfig) === null || _b === void 0 ? void 0 : _b.createReactContainer;
1323
+ vue.watchEffect(() => {
1324
+ var _a, _b, _c;
1325
+ if (!createReactContainer) {
1326
+ return;
1327
+ }
1328
+ const pluginService = (_c = (_b = (_a = tableRef.value) === null || _a === void 0 ? void 0 : _a.scenegraph) === null || _b === void 0 ? void 0 : _b.stage) === null || _c === void 0 ? void 0 : _c.pluginService;
1329
+ if (!pluginService) {
1330
+ return;
1331
+ }
1332
+ const exist = pluginService.findPluginsByName('VTableVueAttributePlugin');
1333
+ if (vutils.isArray(exist) && !!exist.length) {
1334
+ return;
1335
+ }
1336
+ const plugin = new VTableVueAttributePlugin(instance === null || instance === void 0 ? void 0 : instance.appContext);
1337
+ pluginService.register(plugin);
1338
+ });
1008
1339
  }
1009
1340
 
1010
- var _sfc_main$3 = vue.defineComponent({
1011
- __name: 'base-table',
1012
- props: {
1013
- type: { type: String, required: false },
1014
- options: { type: null, required: false },
1015
- records: { type: Array, required: false },
1016
- width: { type: [Number, String], required: false, default: '100%' },
1017
- height: { type: [Number, String], required: false, default: '100%' },
1018
- onReady: { type: Function, required: false },
1019
- onError: { type: Function, required: false },
1020
- keepColumnWidthChange: { type: Boolean, required: false },
1021
- onClickCell: { type: Function, required: false },
1022
- onDblClickCell: { type: Function, required: false },
1023
- onMouseDownCell: { type: Function, required: false },
1024
- onMouseUpCell: { type: Function, required: false },
1025
- onSelectedCell: { type: Function, required: false },
1026
- onKeyDown: { type: Function, required: false },
1027
- onMouseEnterTable: { type: Function, required: false },
1028
- onMouseLeaveTable: { type: Function, required: false },
1029
- onMouseDownTable: { type: Function, required: false },
1030
- onMouseMoveCell: { type: Function, required: false },
1031
- onMouseEnterCell: { type: Function, required: false },
1032
- onMouseLeaveCell: { type: Function, required: false },
1033
- onContextMenuCell: { type: Function, required: false },
1034
- onContextMenuCanvas: { type: Function, required: false },
1035
- onResizeColumn: { type: Function, required: false },
1036
- onResizeColumnEnd: { type: Function, required: false },
1037
- onChangeHeaderPosition: { type: Function, required: false },
1038
- onChangeHeaderPositionStart: { type: Function, required: false },
1039
- onChangeHeaderPositionFail: { type: Function, required: false },
1040
- onSortClick: { type: Function, required: false },
1041
- onFreezeClick: { type: Function, required: false },
1042
- onScroll: { type: Function, required: false },
1043
- onDropdownMenuClick: { type: Function, required: false },
1044
- onMouseOverChartSymbol: { type: Function, required: false },
1045
- onDragSelectEnd: { type: Function, required: false },
1046
- onDropdownIconClick: { type: Function, required: false },
1047
- onDropdownMenuClear: { type: Function, required: false },
1048
- onTreeHierarchyStateChange: { type: Function, required: false },
1049
- onShowMenu: { type: Function, required: false },
1050
- onHideMenu: { type: Function, required: false },
1051
- onIconClick: { type: Function, required: false },
1052
- onLegendItemClick: { type: Function, required: false },
1053
- onLegendItemHover: { type: Function, required: false },
1054
- onLegendItemUnHover: { type: Function, required: false },
1055
- onLegendChange: { type: Function, required: false },
1056
- onMouseEnterAxis: { type: Function, required: false },
1057
- onMouseLeaveAxis: { type: Function, required: false },
1058
- onCheckboxStateChange: { type: Function, required: false },
1059
- onRadioStateChange: { type: Function, required: false },
1060
- onAfterRender: { type: Function, required: false },
1061
- onInitialized: { type: Function, required: false },
1062
- onPivotSortClick: { type: Function, required: false },
1063
- onDrillMenuClick: { type: Function, required: false },
1064
- onVChartEventType: { type: Function, required: false },
1065
- onChangeCellValue: { type: Function, required: false },
1066
- onMousedownFillHandle: { type: Function, required: false },
1067
- onDragFillHandleEnd: { type: Function, required: false },
1068
- onDblclickFillHandle: { type: Function, required: false },
1069
- onScrollVerticalEnd: { type: Function, required: false },
1070
- onScrollHorizontalEnd: { type: Function, required: false },
1071
- onChangCellValue: { type: Function, required: false },
1072
- onEmptyTipClick: { type: Function, required: false },
1073
- onEmptyTipDblClick: { type: Function, required: false },
1074
- onButtonClick: { type: Function, required: false },
1075
- onBeforeCacheChartImage: { type: Function, required: false },
1076
- onPastedData: { type: Function, required: false }
1077
- },
1078
- emits: TABLE_EVENTS_KEYS,
1079
- setup(__props, { expose: __expose, emit: __emit }) {
1080
- const props = __props;
1081
- const vTableContainer = vue.ref(null);
1082
- const vTableInstance = vue.shallowRef(null);
1083
- const columnWidths = vue.ref(new Map());
1084
- const pivotColumnWidths = vue.ref([]);
1085
- const pivotHeaderColumnWidths = vue.ref([]);
1086
- useEditorRender(props, vTableInstance);
1087
- useCellRender(props, vTableInstance);
1088
- __expose({ vTableInstance });
1089
- const containerWidth = vue.computed(() => (typeof props.width === 'number' ? `${props.width}px` : props.width));
1090
- const containerHeight = vue.computed(() => (typeof props.height === 'number' ? `${props.height}px` : props.height));
1091
- const emit = __emit;
1092
- const bindEvents = (instance) => {
1093
- TABLE_EVENTS_KEYS.forEach(eventKey => {
1094
- const vueEventHandler = (event) => {
1095
- emit(eventKey, event);
1096
- };
1097
- instance.on(TABLE_EVENTS[eventKey], vueEventHandler);
1098
- });
1099
- };
1100
- const createTableInstance = (Type, options) => {
1101
- const vtable = new Type(vTableContainer.value, options);
1102
- vTableInstance.value = vtable;
1103
- columnWidths.value.clear();
1104
- pivotColumnWidths.value = [];
1105
- pivotHeaderColumnWidths.value = [];
1106
- vtable.on('resize_column_end', (args) => {
1107
- if (!props.keepColumnWidthChange) {
1108
- return;
1109
- }
1110
- const { col, colWidths } = args;
1111
- const width = colWidths[col];
1112
- if (vtable.isPivotTable()) {
1113
- const path = vtable.getCellHeaderPaths(col, vtable.columnHeaderLevelCount);
1114
- let dimensions = null;
1115
- if (path.cellLocation === 'rowHeader') {
1116
- dimensions = path.rowHeaderPaths;
1117
- }
1118
- else {
1119
- dimensions = path.colHeaderPaths;
1120
- }
1121
- let found = false;
1122
- for (let i = 0; i < pivotColumnWidths.value.length; i++) {
1123
- const item = pivotColumnWidths.value[i];
1124
- if (JSON.stringify(item.dimensions) === JSON.stringify(dimensions)) {
1125
- item.width = width;
1126
- found = true;
1127
- }
1128
- }
1129
- if (!found) {
1130
- pivotColumnWidths.value.push({ dimensions, width });
1131
- }
1132
- }
1133
- else {
1134
- const define = vtable.getBodyColumnDefine(col, 0);
1135
- if (define?.key) {
1136
- columnWidths.value.set(define.key, width);
1137
- }
1138
- }
1139
- });
1140
- };
1141
- const createVTable = () => {
1142
- if (!vTableContainer.value) {
1143
- return;
1144
- }
1145
- if (vTableInstance.value) {
1146
- vTableInstance.value.release();
1147
- }
1148
- const getRecords = () => {
1149
- return props.records !== undefined && props.records !== null && props.records.length > 0
1150
- ? props.records
1151
- : props.options.records;
1152
- };
1153
- try {
1154
- switch (props.type) {
1155
- case 'list':
1156
- createTableInstance(VTable.ListTable, {
1157
- ...props.options,
1158
- records: getRecords()
1159
- });
1160
- break;
1161
- case 'pivot':
1162
- createTableInstance(VTable.PivotTable, {
1163
- ...props.options,
1164
- records: getRecords()
1165
- });
1166
- break;
1167
- case 'chart':
1168
- createTableInstance(VTable.PivotChart, {
1169
- ...props.options,
1170
- records: getRecords()
1171
- });
1172
- break;
1173
- }
1174
- bindEvents(vTableInstance.value);
1175
- props.onReady?.(vTableInstance.value, true);
1176
- }
1177
- catch (err) {
1178
- props.onError?.(err);
1179
- }
1180
- };
1181
- const updateVTable = (newOptions) => {
1182
- if (!vTableInstance.value) {
1183
- return;
1184
- }
1185
- try {
1186
- if (props.keepColumnWidthChange) {
1187
- const columnWidthConfig = updateWidthCache(columnWidths.value, pivotColumnWidths.value, vTableInstance.value);
1188
- newOptions = {
1189
- ...newOptions,
1190
- columnWidthConfig: columnWidthConfig,
1191
- columnWidthConfigForRowHeader: columnWidthConfig
1192
- };
1193
- }
1194
- switch (props.type) {
1195
- case 'list':
1196
- if (vTableInstance.value instanceof VTable.ListTable) {
1197
- vTableInstance.value.updateOption(newOptions);
1198
- }
1199
- break;
1200
- case 'pivot':
1201
- if (vTableInstance.value instanceof VTable.PivotTable) {
1202
- vTableInstance.value.updateOption(newOptions);
1203
- }
1204
- break;
1205
- case 'chart':
1206
- if (vTableInstance.value instanceof VTable.PivotChart) {
1207
- vTableInstance.value.updateOption(newOptions);
1208
- }
1209
- break;
1210
- }
1211
- }
1212
- catch (err) {
1213
- props.onError?.(err);
1214
- }
1215
- };
1216
- vue.onMounted(createVTable);
1217
- vue.onBeforeUnmount(() => {
1218
- vTableInstance.value?.release();
1219
- });
1220
- vue.watch(() => props.options, (newOptions, oldOptions) => {
1221
- if (vTableInstance.value) {
1222
- updateVTable(newOptions);
1223
- }
1224
- else {
1225
- createVTable();
1226
- }
1227
- });
1228
- vue.watch(() => props.records, (newRecords, oldRecords) => {
1229
- if (vTableInstance.value) {
1230
- updateVTable({ ...props.options, records: newRecords });
1231
- }
1232
- else {
1233
- createVTable();
1234
- }
1235
- }, { deep: true });
1236
- function updateWidthCache(columnWidths, pivotColumnWidths, table) {
1237
- if (table.isPivotTable()) {
1238
- return pivotColumnWidths;
1239
- }
1240
- const columnWidthConfig = [];
1241
- columnWidths.forEach((width, key) => {
1242
- columnWidthConfig.push({
1243
- key,
1244
- width
1245
- });
1246
- });
1247
- return columnWidthConfig;
1248
- }
1249
- return (_ctx, _cache) => {
1250
- return (vue.openBlock(), vue.createElementBlock("div", {
1251
- ref_key: "vTableContainer",
1252
- ref: vTableContainer,
1253
- style: vue.normalizeStyle([{ width: containerWidth.value, height: containerHeight.value }, { "position": "relative" }])
1254
- }, null, 4));
1255
- };
1256
- }
1341
+ // 创建表格实例
1342
+ // use Constructor<T> will cause error in rollup-plugin-typescript2, use any temporarily
1343
+ var _sfc_main$3 = /*@__PURE__*/ vue.defineComponent({
1344
+ __name: 'base-table',
1345
+ props: {
1346
+ type: { type: String, required: false },
1347
+ options: { type: null, required: false },
1348
+ records: { type: Array, required: false },
1349
+ width: { type: [Number, String], required: false, default: '100%' },
1350
+ height: { type: [Number, String], required: false, default: '100%' },
1351
+ onReady: { type: Function, required: false },
1352
+ onError: { type: Function, required: false },
1353
+ keepColumnWidthChange: { type: Boolean, required: false },
1354
+ onClickCell: { type: Function, required: false },
1355
+ onDblClickCell: { type: Function, required: false },
1356
+ onMouseDownCell: { type: Function, required: false },
1357
+ onMouseUpCell: { type: Function, required: false },
1358
+ onSelectedCell: { type: Function, required: false },
1359
+ onKeyDown: { type: Function, required: false },
1360
+ onMouseEnterTable: { type: Function, required: false },
1361
+ onMouseLeaveTable: { type: Function, required: false },
1362
+ onMouseDownTable: { type: Function, required: false },
1363
+ onMouseMoveCell: { type: Function, required: false },
1364
+ onMouseEnterCell: { type: Function, required: false },
1365
+ onMouseLeaveCell: { type: Function, required: false },
1366
+ onContextMenuCell: { type: Function, required: false },
1367
+ onContextMenuCanvas: { type: Function, required: false },
1368
+ onResizeColumn: { type: Function, required: false },
1369
+ onResizeColumnEnd: { type: Function, required: false },
1370
+ onChangeHeaderPosition: { type: Function, required: false },
1371
+ onChangeHeaderPositionStart: { type: Function, required: false },
1372
+ onChangeHeaderPositionFail: { type: Function, required: false },
1373
+ onSortClick: { type: Function, required: false },
1374
+ onFreezeClick: { type: Function, required: false },
1375
+ onScroll: { type: Function, required: false },
1376
+ onDropdownMenuClick: { type: Function, required: false },
1377
+ onMouseOverChartSymbol: { type: Function, required: false },
1378
+ onDragSelectEnd: { type: Function, required: false },
1379
+ onDropdownIconClick: { type: Function, required: false },
1380
+ onDropdownMenuClear: { type: Function, required: false },
1381
+ onTreeHierarchyStateChange: { type: Function, required: false },
1382
+ onShowMenu: { type: Function, required: false },
1383
+ onHideMenu: { type: Function, required: false },
1384
+ onIconClick: { type: Function, required: false },
1385
+ onLegendItemClick: { type: Function, required: false },
1386
+ onLegendItemHover: { type: Function, required: false },
1387
+ onLegendItemUnHover: { type: Function, required: false },
1388
+ onLegendChange: { type: Function, required: false },
1389
+ onMouseEnterAxis: { type: Function, required: false },
1390
+ onMouseLeaveAxis: { type: Function, required: false },
1391
+ onCheckboxStateChange: { type: Function, required: false },
1392
+ onRadioStateChange: { type: Function, required: false },
1393
+ onAfterRender: { type: Function, required: false },
1394
+ onInitialized: { type: Function, required: false },
1395
+ onPivotSortClick: { type: Function, required: false },
1396
+ onDrillMenuClick: { type: Function, required: false },
1397
+ onVChartEventType: { type: Function, required: false },
1398
+ onChangeCellValue: { type: Function, required: false },
1399
+ onMousedownFillHandle: { type: Function, required: false },
1400
+ onDragFillHandleEnd: { type: Function, required: false },
1401
+ onDblclickFillHandle: { type: Function, required: false },
1402
+ onScrollVerticalEnd: { type: Function, required: false },
1403
+ onScrollHorizontalEnd: { type: Function, required: false },
1404
+ onChangCellValue: { type: Function, required: false },
1405
+ onEmptyTipClick: { type: Function, required: false },
1406
+ onEmptyTipDblClick: { type: Function, required: false },
1407
+ onButtonClick: { type: Function, required: false },
1408
+ onBeforeCacheChartImage: { type: Function, required: false },
1409
+ onPastedData: { type: Function, required: false }
1410
+ },
1411
+ emits: TABLE_EVENTS_KEYS,
1412
+ setup(__props, { expose: __expose, emit: __emit }) {
1413
+ const props = __props;
1414
+ // 创建用于引用 DOM 元素和表格实例的 ref
1415
+ const vTableContainer = vue.ref(null);
1416
+ const vTableInstance = vue.shallowRef(null);
1417
+ // for keepColumnWidthChange
1418
+ const columnWidths = vue.ref(new Map());
1419
+ const pivotColumnWidths = vue.ref([]);
1420
+ const pivotHeaderColumnWidths = vue.ref([]);
1421
+ // 自定义编辑渲染器
1422
+ useEditorRender(props, vTableInstance);
1423
+ // 自定义单元格渲染器
1424
+ useCellRender(props, vTableInstance);
1425
+ // 公开 vTableInstance,以便外部组件可以访问
1426
+ __expose({ vTableInstance });
1427
+ // 计算容器的宽度和高度
1428
+ const containerWidth = vue.computed(() => (typeof props.width === 'number' ? `${props.width}px` : props.width));
1429
+ const containerHeight = vue.computed(() => (typeof props.height === 'number' ? `${props.height}px` : props.height));
1430
+ // 绑定事件到表格实例
1431
+ const emit = __emit;
1432
+ const bindEvents = (instance) => {
1433
+ TABLE_EVENTS_KEYS.forEach(eventKey => {
1434
+ const vueEventHandler = (event) => {
1435
+ emit(eventKey, event);
1436
+ };
1437
+ instance.on(TABLE_EVENTS[eventKey], vueEventHandler);
1438
+ });
1439
+ };
1440
+ const createTableInstance = (Type, options) => {
1441
+ const vtable = new Type(vTableContainer.value, options);
1442
+ vTableInstance.value = vtable;
1443
+ // for keepColumnWidthChange
1444
+ columnWidths.value.clear();
1445
+ pivotColumnWidths.value = [];
1446
+ pivotHeaderColumnWidths.value = [];
1447
+ vtable.on('resize_column_end', (args) => {
1448
+ // const table = vTableInstance.value;
1449
+ if (!props.keepColumnWidthChange) {
1450
+ return;
1451
+ }
1452
+ const { col, colWidths } = args;
1453
+ const width = colWidths[col];
1454
+ if (vtable.isPivotTable()) {
1455
+ const path = vtable.getCellHeaderPaths(col, vtable.columnHeaderLevelCount);
1456
+ let dimensions = null;
1457
+ if (path.cellLocation === 'rowHeader') {
1458
+ dimensions = path.rowHeaderPaths;
1459
+ }
1460
+ else {
1461
+ dimensions = path.colHeaderPaths;
1462
+ }
1463
+ let found = false;
1464
+ // pivotColumnWidths.value.forEach(item => {
1465
+ // if (JSON.stringify(item.dimensions) === JSON.stringify(dimensions)) {
1466
+ // item.width = width;
1467
+ // found = true;
1468
+ // }
1469
+ // });
1470
+ for (let i = 0; i < pivotColumnWidths.value.length; i++) {
1471
+ const item = pivotColumnWidths.value[i];
1472
+ if (JSON.stringify(item.dimensions) === JSON.stringify(dimensions)) {
1473
+ item.width = width;
1474
+ found = true;
1475
+ }
1476
+ }
1477
+ if (!found) {
1478
+ pivotColumnWidths.value.push({ dimensions, width });
1479
+ }
1480
+ }
1481
+ else {
1482
+ const define = vtable.getBodyColumnDefine(col, 0);
1483
+ if (define === null || define === void 0 ? void 0 : define.key) {
1484
+ columnWidths.value.set(define.key, width);
1485
+ }
1486
+ }
1487
+ });
1488
+ };
1489
+ const createVTable = () => {
1490
+ var _a, _b;
1491
+ if (!vTableContainer.value) {
1492
+ return;
1493
+ }
1494
+ if (vTableInstance.value) {
1495
+ vTableInstance.value.release();
1496
+ }
1497
+ const getRecords = () => {
1498
+ return props.records !== undefined && props.records !== null && props.records.length > 0
1499
+ ? props.records
1500
+ : props.options.records;
1501
+ };
1502
+ try {
1503
+ switch (props.type) {
1504
+ case 'list':
1505
+ createTableInstance(VTable.ListTable, Object.assign(Object.assign({}, props.options), { records: getRecords() }));
1506
+ break;
1507
+ case 'pivot':
1508
+ createTableInstance(VTable.PivotTable, Object.assign(Object.assign({}, props.options), { records: getRecords() }));
1509
+ break;
1510
+ case 'chart':
1511
+ createTableInstance(VTable.PivotChart, Object.assign(Object.assign({}, props.options), { records: getRecords() }));
1512
+ break;
1513
+ }
1514
+ bindEvents(vTableInstance.value);
1515
+ (_a = props.onReady) === null || _a === void 0 ? void 0 : _a.call(props, vTableInstance.value, true);
1516
+ }
1517
+ catch (err) {
1518
+ (_b = props.onError) === null || _b === void 0 ? void 0 : _b.call(props, err);
1519
+ }
1520
+ };
1521
+ // 更新表格实例
1522
+ const updateVTable = (newOptions) => {
1523
+ var _a;
1524
+ if (!vTableInstance.value) {
1525
+ return;
1526
+ }
1527
+ try {
1528
+ // for keepColumnWidthChange, update column width
1529
+ if (props.keepColumnWidthChange) {
1530
+ const columnWidthConfig = updateWidthCache(columnWidths.value, pivotColumnWidths.value, vTableInstance.value);
1531
+ newOptions = Object.assign(Object.assign({}, newOptions), { columnWidthConfig: columnWidthConfig, columnWidthConfigForRowHeader: columnWidthConfig });
1532
+ }
1533
+ switch (props.type) {
1534
+ case 'list':
1535
+ if (vTableInstance.value instanceof VTable.ListTable) {
1536
+ vTableInstance.value.updateOption(newOptions);
1537
+ }
1538
+ break;
1539
+ case 'pivot':
1540
+ if (vTableInstance.value instanceof VTable.PivotTable) {
1541
+ vTableInstance.value.updateOption(newOptions);
1542
+ }
1543
+ break;
1544
+ case 'chart':
1545
+ if (vTableInstance.value instanceof VTable.PivotChart) {
1546
+ vTableInstance.value.updateOption(newOptions);
1547
+ }
1548
+ break;
1549
+ }
1550
+ }
1551
+ catch (err) {
1552
+ (_a = props.onError) === null || _a === void 0 ? void 0 : _a.call(props, err);
1553
+ }
1554
+ };
1555
+ // 组件挂载时创建表格
1556
+ vue.onMounted(createVTable);
1557
+ vue.onBeforeUnmount(() => {
1558
+ var _a;
1559
+ (_a = vTableInstance.value) === null || _a === void 0 ? void 0 : _a.release();
1560
+ });
1561
+ // 监听 options 属性的变化
1562
+ // 需要去做细颗粒度的比较
1563
+ // deep 选中会导致tree失效
1564
+ vue.watch(() => props.options, (newOptions, oldOptions) => {
1565
+ if (vTableInstance.value) {
1566
+ updateVTable(newOptions);
1567
+ }
1568
+ else {
1569
+ createVTable();
1570
+ }
1571
+ }
1572
+ // { deep: true },
1573
+ );
1574
+ // 监听 records 属性的变化并更新表格
1575
+ // 需要去做细颗粒度的比较
1576
+ vue.watch(() => props.records, (newRecords, oldRecords) => {
1577
+ // if (!isEqual(newRecords, oldRecords)) {
1578
+ if (vTableInstance.value) {
1579
+ updateVTable(Object.assign(Object.assign({}, props.options), { records: newRecords }));
1580
+ }
1581
+ else {
1582
+ createVTable();
1583
+ }
1584
+ // }
1585
+ }, { deep: true });
1586
+ function updateWidthCache(columnWidths, pivotColumnWidths, table) {
1587
+ if (table.isPivotTable()) {
1588
+ return pivotColumnWidths;
1589
+ }
1590
+ const columnWidthConfig = [];
1591
+ columnWidths.forEach((width, key) => {
1592
+ columnWidthConfig.push({
1593
+ key,
1594
+ width
1595
+ });
1596
+ });
1597
+ return columnWidthConfig;
1598
+ }
1599
+ return (_ctx, _cache) => {
1600
+ return (vue.openBlock(), vue.createElementBlock("div", {
1601
+ ref_key: "vTableContainer",
1602
+ ref: vTableContainer,
1603
+ style: vue.normalizeStyle([{ width: containerWidth.value, height: containerHeight.value }, { "position": "relative" }])
1604
+ }, null, 4 /* STYLE */));
1605
+ };
1606
+ }
1257
1607
  });
1258
1608
 
1259
- var _sfc_main$2 = vue.defineComponent({
1260
- __name: 'list-table',
1261
- props: {
1262
- options: { type: Object, required: true },
1263
- records: { type: Array, required: false },
1264
- width: { type: [String, Number], required: false },
1265
- height: { type: [String, Number], required: false }
1266
- },
1267
- setup(__props, { expose: __expose }) {
1268
- const props = __props;
1269
- const baseTableRef = vue.ref(null);
1270
- const slots = vue.useSlots();
1271
- const computedOptions = vue.computed(() => {
1272
- const flattenedSlots = flattenVNodes(slots.default?.() || []);
1273
- const slotOptions = extractListSlotOptions(flattenedSlots);
1274
- return mergeSlotOptions(props.options, slotOptions);
1275
- });
1276
- __expose({
1277
- vTableInstance: vue.computed(() => baseTableRef.value?.vTableInstance || null),
1278
- });
1279
- return (_ctx, _cache) => {
1280
- return (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
1281
- vue.createVNode(_sfc_main$3, vue.mergeProps({
1282
- type: "list",
1283
- options: computedOptions.value,
1284
- records: __props.records,
1285
- width: __props.width,
1286
- height: __props.height,
1287
- ref_key: "baseTableRef",
1288
- ref: baseTableRef
1289
- }, _ctx.$attrs), null, 16, ["options", "records", "width", "height"]),
1290
- vue.renderSlot(_ctx.$slots, "default")
1291
- ], 64));
1292
- };
1293
- }
1609
+ // 定义属性
1610
+ var _sfc_main$2 = /*@__PURE__*/ vue.defineComponent({
1611
+ __name: 'list-table',
1612
+ props: {
1613
+ options: { type: Object, required: true },
1614
+ records: { type: Array, required: false },
1615
+ width: { type: [String, Number], required: false },
1616
+ height: { type: [String, Number], required: false }
1617
+ },
1618
+ setup(__props, { expose: __expose }) {
1619
+ const props = __props;
1620
+ // 引用BaseTable实例
1621
+ const baseTableRef = vue.ref(null);
1622
+ const slots = vue.useSlots();
1623
+ // 合并插槽配置
1624
+ const computedOptions = vue.computed(() => {
1625
+ var _a;
1626
+ const flattenedSlots = flattenVNodes(((_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)) || []);
1627
+ const slotOptions = extractListSlotOptions(flattenedSlots);
1628
+ return mergeSlotOptions(props.options, slotOptions);
1629
+ });
1630
+ // 暴露实例
1631
+ __expose({
1632
+ vTableInstance: vue.computed(() => { var _a; return ((_a = baseTableRef.value) === null || _a === void 0 ? void 0 : _a.vTableInstance) || null; }),
1633
+ });
1634
+ return (_ctx, _cache) => {
1635
+ return (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
1636
+ vue.createVNode(_sfc_main$3, vue.mergeProps({
1637
+ type: "list",
1638
+ options: computedOptions.value,
1639
+ records: __props.records,
1640
+ width: __props.width,
1641
+ height: __props.height,
1642
+ ref_key: "baseTableRef",
1643
+ ref: baseTableRef
1644
+ }, _ctx.$attrs), null, 16 /* FULL_PROPS */, ["options", "records", "width", "height"]),
1645
+ vue.renderSlot(_ctx.$slots, "default")
1646
+ ], 64 /* STABLE_FRAGMENT */));
1647
+ };
1648
+ }
1294
1649
  });
1295
1650
 
1296
- var _sfc_main$1 = vue.defineComponent({
1297
- __name: 'pivot-table',
1298
- props: {
1299
- options: { type: Object, required: true },
1300
- records: { type: Array, required: false },
1301
- width: { type: [String, Number], required: false },
1302
- height: { type: [String, Number], required: false }
1303
- },
1304
- setup(__props, { expose: __expose }) {
1305
- const props = __props;
1306
- const baseTableRef = vue.shallowRef(null);
1307
- const slots = vue.useSlots();
1308
- const computedOptions = vue.computed(() => {
1309
- const flattenedSlots = flattenVNodes(slots.default?.() || []);
1310
- const slotOptions = extractPivotSlotOptions(flattenedSlots);
1311
- return mergeSlotOptions(props.options, slotOptions);
1312
- });
1313
- __expose({ vTableInstance: vue.computed(() => baseTableRef.value?.vTableInstance || null) });
1314
- return (_ctx, _cache) => {
1315
- return (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
1316
- vue.createVNode(_sfc_main$3, vue.mergeProps({
1317
- type: "pivot",
1318
- options: computedOptions.value,
1319
- records: __props.records,
1320
- width: __props.width,
1321
- height: __props.height,
1322
- ref_key: "baseTableRef",
1323
- ref: baseTableRef
1324
- }, _ctx.$attrs), null, 16, ["options", "records", "width", "height"]),
1325
- vue.renderSlot(_ctx.$slots, "default")
1326
- ], 64));
1327
- };
1328
- }
1651
+ var _sfc_main$1 = /*@__PURE__*/ vue.defineComponent({
1652
+ __name: 'pivot-table',
1653
+ props: {
1654
+ options: { type: Object, required: true },
1655
+ records: { type: Array, required: false },
1656
+ width: { type: [String, Number], required: false },
1657
+ height: { type: [String, Number], required: false }
1658
+ },
1659
+ setup(__props, { expose: __expose }) {
1660
+ const props = __props;
1661
+ const baseTableRef = vue.shallowRef(null);
1662
+ const slots = vue.useSlots();
1663
+ const computedOptions = vue.computed(() => {
1664
+ var _a;
1665
+ const flattenedSlots = flattenVNodes(((_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)) || []);
1666
+ const slotOptions = extractPivotSlotOptions(flattenedSlots);
1667
+ return mergeSlotOptions(props.options, slotOptions);
1668
+ });
1669
+ __expose({ vTableInstance: vue.computed(() => { var _a; return ((_a = baseTableRef.value) === null || _a === void 0 ? void 0 : _a.vTableInstance) || null; }) });
1670
+ return (_ctx, _cache) => {
1671
+ return (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
1672
+ vue.createVNode(_sfc_main$3, vue.mergeProps({
1673
+ type: "pivot",
1674
+ options: computedOptions.value,
1675
+ records: __props.records,
1676
+ width: __props.width,
1677
+ height: __props.height,
1678
+ ref_key: "baseTableRef",
1679
+ ref: baseTableRef
1680
+ }, _ctx.$attrs), null, 16 /* FULL_PROPS */, ["options", "records", "width", "height"]),
1681
+ vue.renderSlot(_ctx.$slots, "default")
1682
+ ], 64 /* STABLE_FRAGMENT */));
1683
+ };
1684
+ }
1329
1685
  });
1330
1686
 
1331
- var _sfc_main = vue.defineComponent({
1332
- __name: 'pivot-chart',
1333
- props: {
1334
- options: { type: Object, required: true },
1335
- records: { type: Array, required: false },
1336
- width: { type: [String, Number], required: false },
1337
- height: { type: [String, Number], required: false }
1338
- },
1339
- setup(__props, { expose: __expose }) {
1340
- const props = __props;
1341
- const baseTableRef = vue.shallowRef(null);
1342
- const slots = vue.useSlots();
1343
- const computedOptions = vue.computed(() => {
1344
- const flattenedSlots = flattenVNodes(slots.default?.() || []);
1345
- const slotOptions = extractPivotSlotOptions(flattenedSlots);
1346
- return mergeSlotOptions(props.options, slotOptions);
1347
- });
1348
- __expose({ vTableInstance: vue.computed(() => baseTableRef.value?.vTableInstance || null) });
1349
- return (_ctx, _cache) => {
1350
- return (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
1351
- vue.createVNode(_sfc_main$3, vue.mergeProps({
1352
- type: "chart",
1353
- options: computedOptions.value,
1354
- records: __props.records,
1355
- width: __props.width,
1356
- height: __props.height,
1357
- ref_key: "baseTableRef",
1358
- ref: baseTableRef
1359
- }, _ctx.$attrs), null, 16, ["options", "records", "width", "height"]),
1360
- vue.renderSlot(_ctx.$slots, "default")
1361
- ], 64));
1362
- };
1363
- }
1687
+ var _sfc_main = /*@__PURE__*/ vue.defineComponent({
1688
+ __name: 'pivot-chart',
1689
+ props: {
1690
+ options: { type: Object, required: true },
1691
+ records: { type: Array, required: false },
1692
+ width: { type: [String, Number], required: false },
1693
+ height: { type: [String, Number], required: false }
1694
+ },
1695
+ setup(__props, { expose: __expose }) {
1696
+ const props = __props;
1697
+ const baseTableRef = vue.shallowRef(null);
1698
+ const slots = vue.useSlots();
1699
+ const computedOptions = vue.computed(() => {
1700
+ var _a;
1701
+ const flattenedSlots = flattenVNodes(((_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)) || []);
1702
+ const slotOptions = extractPivotSlotOptions(flattenedSlots);
1703
+ return mergeSlotOptions(props.options, slotOptions);
1704
+ });
1705
+ __expose({ vTableInstance: vue.computed(() => { var _a; return ((_a = baseTableRef.value) === null || _a === void 0 ? void 0 : _a.vTableInstance) || null; }) });
1706
+ return (_ctx, _cache) => {
1707
+ return (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, [
1708
+ vue.createVNode(_sfc_main$3, vue.mergeProps({
1709
+ type: "chart",
1710
+ options: computedOptions.value,
1711
+ records: __props.records,
1712
+ width: __props.width,
1713
+ height: __props.height,
1714
+ ref_key: "baseTableRef",
1715
+ ref: baseTableRef
1716
+ }, _ctx.$attrs), null, 16 /* FULL_PROPS */, ["options", "records", "width", "height"]),
1717
+ vue.renderSlot(_ctx.$slots, "default")
1718
+ ], 64 /* STABLE_FRAGMENT */));
1719
+ };
1720
+ }
1364
1721
  });
1365
1722
 
1366
- const registerChartModule = (name, chart) => {
1367
- VTable__namespace.register.chartModule(name, chart);
1723
+ const registerChartModule = (name, chart) => {
1724
+ VTable__namespace.register.chartModule(name, chart);
1368
1725
  };
1369
1726
 
1370
- function ListColumn(props) {
1371
- return null;
1372
- }
1727
+ function ListColumn(props) {
1728
+ return null;
1729
+ }
1373
1730
  ListColumn.symbol = 'ListColumn';
1374
1731
 
1375
- function PivotColumnDimension(props) {
1376
- return null;
1377
- }
1732
+ function PivotColumnDimension(props) {
1733
+ return null;
1734
+ }
1378
1735
  PivotColumnDimension.symbol = 'PivotColumnDimension';
1379
1736
 
1380
- function PivotRowDimension(props) {
1381
- return null;
1382
- }
1737
+ function PivotRowDimension(props) {
1738
+ return null;
1739
+ }
1383
1740
  PivotRowDimension.symbol = 'PivotRowDimension';
1384
1741
 
1385
- function PivotColumnHeaderTitle(props) {
1386
- return null;
1387
- }
1742
+ function PivotColumnHeaderTitle(props) {
1743
+ return null;
1744
+ }
1388
1745
  PivotColumnHeaderTitle.symbol = 'PivotColumnHeaderTitle';
1389
1746
 
1390
- function PivotRowHeaderTitle(props) {
1391
- return null;
1392
- }
1747
+ function PivotRowHeaderTitle(props) {
1748
+ return null;
1749
+ }
1393
1750
  PivotRowHeaderTitle.symbol = 'PivotRowHeaderTitle';
1394
1751
 
1395
- function PivotIndicator(props) {
1396
- return null;
1397
- }
1752
+ function PivotIndicator(props) {
1753
+ return null;
1754
+ }
1398
1755
  PivotIndicator.symbol = 'PivotIndicator';
1399
1756
 
1400
- function PivotCorner(props) {
1401
- return null;
1402
- }
1757
+ function PivotCorner(props) {
1758
+ return null;
1759
+ }
1403
1760
  PivotCorner.symbol = 'PivotCorner';
1404
1761
 
1405
- function Menu(props) {
1406
- return null;
1407
- }
1762
+ function Menu(props) {
1763
+ return null;
1764
+ }
1408
1765
  Menu.symbol = 'Menu';
1409
1766
 
1410
- function Tooltip(props) {
1411
- return null;
1412
- }
1767
+ function Tooltip(props) {
1768
+ return null;
1769
+ }
1413
1770
  Tooltip.symbol = 'Tooltip';
1414
1771
 
1415
- function Group() {
1416
- return null;
1417
- }
1772
+ function Group() {
1773
+ return null;
1774
+ }
1418
1775
  Group.symbol = 'Group';
1419
1776
 
1420
- function Image() {
1421
- return null;
1422
- }
1777
+ function Image() {
1778
+ return null;
1779
+ }
1423
1780
  Image.symbol = 'Image';
1424
1781
 
1425
- function Text() {
1426
- return null;
1427
- }
1782
+ function Text() {
1783
+ return null;
1784
+ }
1428
1785
  Text.symbol = 'Text';
1429
1786
 
1430
- function Tag(props) {
1431
- return null;
1432
- }
1787
+ function Tag(props) {
1788
+ return null;
1789
+ }
1433
1790
  Tag.symbol = 'Tag';
1434
1791
 
1435
- function Radio(props) {
1436
- return null;
1437
- }
1792
+ function Radio(props) {
1793
+ return null;
1794
+ }
1438
1795
  Radio.symbol = 'Radio';
1439
1796
 
1440
- function CheckBox(props) {
1441
- return null;
1442
- }
1797
+ function CheckBox(props) {
1798
+ return null;
1799
+ }
1443
1800
  CheckBox.symbol = 'CheckBox';
1444
1801
 
1445
- const version = "1.25.1-alpha.0";
1802
+ const version = "1.26.0";
1446
1803
 
1447
1804
  exports.VTable = VTable__namespace;
1448
1805
  Object.defineProperty(exports, 'register', {