umy-ui-table 1.2.3 → 1.2.5
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.
- package/lib/button.js +1 -1
- package/lib/icon.js +1 -1
- package/lib/index.js +1 -1
- package/lib/locale/format.js +1 -1
- package/lib/locale/index.js +1 -72
- package/lib/mixins/locale.js +1 -1
- package/lib/theme-chalk/button.css +1 -1
- package/lib/theme-chalk/icon.css +1 -1
- package/lib/theme-chalk/iconfont.1785242763644.ttf +0 -0
- package/lib/theme-chalk/iconfont.1785242763644.woff +0 -0
- package/lib/theme-chalk/iconfont.1785242763644.woff2 +0 -0
- package/lib/theme-chalk/index.css +1 -1
- package/lib/theme-chalk/u-table.css +1 -1
- package/lib/theme-chalk/ux-grid.css +1 -1
- package/lib/u-table-column.js +1 -1
- package/lib/u-table.js +1 -1
- package/lib/umy-ui.common.js +1 -1
- package/lib/utils/util.js +1 -1
- package/lib/ux-grid.js +1 -1
- package/lib/ux-table-column.js +1 -1
- package/package.json +4 -3
- package/packages/.DS_Store +0 -0
- package/packages/input/.DS_Store +0 -0
- package/packages/pagination/.DS_Store +0 -0
- package/packages/scrollbar/.DS_Store +0 -0
- package/packages/select/.DS_Store +0 -0
- package/packages/table/.DS_Store +0 -0
- package/packages/tag/.DS_Store +0 -0
- package/packages/tools/.DS_Store +0 -0
- package/packages/tools/locale/index.js +2 -48
- package/packages/tools/utils/.DS_Store +0 -0
- package/packages/tooltip/.DS_Store +0 -0
- package/packages/u-table/.DS_Store +0 -0
- package/packages/ux-grid/.DS_Store +0 -0
- package/packages/ux-grid/mixins/index.js +136 -29
- package/packages/ux-grid/src/dialog-draft.js +75 -0
- package/packages/ux-grid/src/element-renderer.js +784 -0
- package/packages/ux-grid/src/grid-height.js +65 -0
- package/packages/ux-grid/src/grid-kernel.js +14 -0
- package/packages/ux-grid/src/setup.js +42 -0
- package/packages/ux-grid/src/ux-grid.vue +225 -44
- package/packages/ux-grid/test/browser-acceptance.cjs +192 -0
- package/packages/ux-grid/test/browser-baseline-loader.cjs +10 -0
- package/packages/ux-grid/test/browser-entry.js +242 -0
- package/packages/ux-grid/test/browser-renderer-contracts.cjs +246 -0
- package/packages/ux-grid/test/browser-renderer-entry.js +129 -0
- package/packages/ux-grid/test/browser-resize-contracts.cjs +150 -0
- package/packages/ux-grid/test/compatibility.cjs +176 -0
- package/packages/ux-grid/test/contracts.cjs +281 -0
- package/packages/ux-grid/test/delivery.cjs +103 -0
- package/packages/ux-grid/test/integration.cjs +132 -0
- package/packages/ux-grid/test/real-kernel-contracts.cjs +335 -0
- package/packages/ux-grid/test/real-kernel-events.cjs +233 -0
- package/packages/ux-grid/test/renderer-boundaries.cjs +165 -0
- package/packages/ux-grid/test/ui-components.cjs +103 -0
- package/tools/locale/format.js +1 -1
- package/tools/locale/index.js +1 -7
- package/tools/mixins/locale.js +1 -1
- package/tools/utils/util.js +1 -1
package/lib/ux-table-column.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist/",n(n.s=
|
|
1
|
+
module.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist/",n(n.s=39)}({35:function(e,t){e.exports=require("vxe-table/lib/column")},39:function(e,t,n){"use strict";n.r(t);var r=n(35),o=n.n(r),u=Object.assign({},o.a,{name:"UxTableColumn"});u.install=function(e){e.component(u.name,u)},t.default=u}});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "umy-ui-table",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "一个基于 vue 的 PC 端表格UI库,解决万级数据渲染卡顿问题,过万数据点击全选卡顿,等等问题",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "foriacus"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"lint": "eslint --fix --ext .js,.vue examples",
|
|
10
10
|
"clean": "rimraf lib && rimraf packages/*/lib",
|
|
11
11
|
"lib:file": "node build/build-entry.js",
|
|
12
|
-
"lib:utils": "cross-env BABEL_ENV=utils babel tools --out-dir lib",
|
|
12
|
+
"lib:utils": "cross-env BABEL_ENV=utils babel tools --out-dir lib && webpack --config build/webpack.locale.js",
|
|
13
13
|
"lib:umd": "node build/build-locale.js",
|
|
14
14
|
"lib:theme": "gulp build",
|
|
15
15
|
"lib": "npm run clean && npm run lib:file && webpack --config build/webpack.conf.js && webpack --config build/webpack.common.js && webpack --config build/webpack.component.js && npm run lib:utils && npm run lib:umd && npm run lib:theme"
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"url": "git+https://github.com/popo-fishes/umy-ui.git"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"babel-helper-vue-jsx-merge-props": "^2.0.0",
|
|
37
38
|
"async-validator": "~1.8.1",
|
|
38
39
|
"deepmerge": "^1.2.0",
|
|
39
40
|
"normalize-wheel": "^1.0.1",
|
|
@@ -41,6 +42,7 @@
|
|
|
41
42
|
"throttle-debounce": "^1.0.1",
|
|
42
43
|
"vuedraggable": "^2.23.2",
|
|
43
44
|
"vxe-table": "^3.22.9",
|
|
45
|
+
"vxe-pc-ui": "3.16.23",
|
|
44
46
|
"@vxe-ui/core": "^3.4.19",
|
|
45
47
|
"xe-utils": ">= 3"
|
|
46
48
|
},
|
|
@@ -54,7 +56,6 @@
|
|
|
54
56
|
"animejs": "^3.1.0",
|
|
55
57
|
"babel-cli": "^6.26.0",
|
|
56
58
|
"babel-core": "^6.26.3",
|
|
57
|
-
"babel-helper-vue-jsx-merge-props": "^2.0.0",
|
|
58
59
|
"babel-loader": "^7.1.5",
|
|
59
60
|
"babel-plugin-add-module-exports": "^0.2.1",
|
|
60
61
|
"babel-plugin-istanbul": "^4.1.1",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,48 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import deepmerge from 'deepmerge';
|
|
4
|
-
import Format from './format';
|
|
5
|
-
|
|
6
|
-
const format = Format(Vue);
|
|
7
|
-
let lang = defaultLang;
|
|
8
|
-
let merged = false;
|
|
9
|
-
let i18nHandler = function() {
|
|
10
|
-
const vuei18n = Object.getPrototypeOf(this || Vue).$t;
|
|
11
|
-
if (typeof vuei18n === 'function' && !!Vue.locale) {
|
|
12
|
-
if (!merged) {
|
|
13
|
-
merged = true;
|
|
14
|
-
Vue.locale(
|
|
15
|
-
Vue.config.lang,
|
|
16
|
-
deepmerge(lang, Vue.locale(Vue.config.lang) || {}, { clone: true })
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
return vuei18n.apply(this, arguments);
|
|
20
|
-
}
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export const t = function(path, options) {
|
|
24
|
-
let value = i18nHandler.apply(this, arguments);
|
|
25
|
-
if (value !== null && value !== undefined) return value;
|
|
26
|
-
const array = path.split('.');
|
|
27
|
-
let current = lang;
|
|
28
|
-
for (let i = 0, j = array.length; i < j; i++) {
|
|
29
|
-
const property = array[i];
|
|
30
|
-
value = current[property];
|
|
31
|
-
if (i === j - 1) {
|
|
32
|
-
return format(value, options)
|
|
33
|
-
}
|
|
34
|
-
if (!value) return '';
|
|
35
|
-
current = value;
|
|
36
|
-
}
|
|
37
|
-
return '';
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export const use = function(l) {
|
|
41
|
-
lang = l || lang;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const i18n = function(fn) {
|
|
45
|
-
i18nHandler = fn || i18nHandler;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export default { use, t, i18n };
|
|
1
|
+
// Table, pagination and the public locale entry share one language store.
|
|
2
|
+
export { default, use, t, i18n } from "../../../tools/locale";
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
import { isArrayFn } from "../../utils/common";
|
|
2
|
+
import { createDialogDraft, mergeDialogDraft } from "../src/dialog-draft";
|
|
3
|
+
// Vue 2 instance listeners ($on/$once) are not included in $listeners.
|
|
4
|
+
function hasGridListener(vm, name) {
|
|
5
|
+
const events = vm._events && vm._events[name];
|
|
6
|
+
return !!((vm.$listeners && vm.$listeners[name]) || (events && events.length));
|
|
7
|
+
}
|
|
8
|
+
function bridgeStoppedClick(vm, params, header) {
|
|
9
|
+
if (vm._isDestroyed || vm._isBeingDestroyed) return;
|
|
10
|
+
const event = params && params.$event;
|
|
11
|
+
if (!event || event.type !== "click" || !event.target || !event.target.closest) return;
|
|
12
|
+
// Only VXE's built-in controls stop propagation. Row/cell-triggered actions
|
|
13
|
+
// must reach the native cell/header handler so current-change stays ordered.
|
|
14
|
+
if (!event.target.closest(".vxe-cell--checkbox,.vxe-cell--radio,.vxe-table--expand-btn,.vxe-cell--tree-btn,.vxe-sort--asc-btn,.vxe-sort--desc-btn")) return;
|
|
15
|
+
if (!hasGridListener(vm, header ? "header-click" : "cell-click") &&
|
|
16
|
+
(header || !hasGridListener(vm, "row-click"))) return;
|
|
17
|
+
const cell = event.target.closest(header ? "th" : "td");
|
|
18
|
+
const table = vm.$refs.singleTable;
|
|
19
|
+
const columnNode = cell && table && table.getColumnNode ? table.getColumnNode(cell) : null;
|
|
20
|
+
const column = params.column || (columnNode && columnNode.item);
|
|
21
|
+
if (!cell || !column) return;
|
|
22
|
+
const payload = Object.assign({}, params, { column, cell });
|
|
23
|
+
if (header) vm.headerClick(payload);
|
|
24
|
+
else vm.cellClick(payload);
|
|
25
|
+
}
|
|
26
|
+
function repeatedClick(vm, key, event) {
|
|
27
|
+
if (!event) return false;
|
|
28
|
+
const seen = vm[key] || (vm[key] = new WeakSet());
|
|
29
|
+
if (seen.has(event)) return true;
|
|
30
|
+
seen.add(event);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
2
33
|
export default {
|
|
34
|
+
beforeDestroy() {
|
|
35
|
+
this.stopDialogSync();
|
|
36
|
+
clearTimeout(this._times);
|
|
37
|
+
this.clearNode();
|
|
38
|
+
},
|
|
3
39
|
props: {
|
|
4
40
|
beautifyTable: { default: false, type: Boolean }, // 美化表格,修改了样式
|
|
5
41
|
showDialogIcon: { default: true, type: Boolean }, // 是否显示操作字段的上下移动按钮(侧滑框)
|
|
@@ -24,6 +60,8 @@ export default {
|
|
|
24
60
|
return { enabled: true, gt: 24, oSize: 0 };
|
|
25
61
|
},
|
|
26
62
|
}, // 横向虚拟滚动配置(列数超过 gt 时启用)
|
|
63
|
+
virtualYConfig: Object, // vxe3 新接口:纵向虚拟滚动(优先于 scrollY)
|
|
64
|
+
virtualXConfig: Object, // vxe3 新接口:横向虚拟滚动(优先于 scrollX)
|
|
27
65
|
widthResize: Boolean,
|
|
28
66
|
mergeCells: Array,
|
|
29
67
|
validConfig: Object, // 校验配置项
|
|
@@ -51,6 +89,7 @@ export default {
|
|
|
51
89
|
columnKey: Boolean, // 是否需要为每一列的 VNode 设置 key 属性(非特殊情况下不需要使用, 常用于拖拽列)
|
|
52
90
|
rowId: String, // 自定义行数据唯一主键的字段名(行数据必须要有唯一主键,默认自动生成)
|
|
53
91
|
highlightCurrentRow: { default: true, type: Boolean }, // 是否要高亮当前行
|
|
92
|
+
highlightHoverRow: { default: true, type: Boolean }, // 鼠标移到行是否要高亮显示
|
|
54
93
|
showAmend: { default: false, type: Boolean }, // 是否显示修改字段名按钮(侧滑框)
|
|
55
94
|
amendBtnIcon: { default: "", type: String }, // 修改字段按钮的图标(侧滑框)
|
|
56
95
|
fieldTitle: { default: "选择显示字段", type: String }, // 弹框的标题(侧滑框)
|
|
@@ -92,9 +131,10 @@ export default {
|
|
|
92
131
|
},
|
|
93
132
|
// 打开自定义字段框
|
|
94
133
|
plDialogOpens() {
|
|
95
|
-
this.
|
|
96
|
-
|
|
97
|
-
this.newDialogData =
|
|
134
|
+
if (this._dialogUnwatch) return;
|
|
135
|
+
this._dialogDraft = createDialogDraft(this.dialogData);
|
|
136
|
+
this.newDialogData = this._dialogDraft.draft.slice();
|
|
137
|
+
this._dialogUnwatch = this.$watch("dialogData", () => this.syncDialogDraft(), { deep: true });
|
|
98
138
|
this.$refs.plDialog.style.width = 300 + "px";
|
|
99
139
|
this._times = setTimeout(() => {
|
|
100
140
|
this.plDialogFals = true;
|
|
@@ -110,31 +150,43 @@ export default {
|
|
|
110
150
|
},
|
|
111
151
|
// 关闭自定义字段框(取消选择)
|
|
112
152
|
closeModal() {
|
|
153
|
+
this.stopDialogSync();
|
|
113
154
|
this.plDialogFals = false;
|
|
114
155
|
clearTimeout(this._times);
|
|
115
156
|
this.$refs.plDialog.style.width = 0 + "px";
|
|
116
|
-
this.aBox.style.display = "none";
|
|
117
157
|
this.clearNode();
|
|
118
158
|
this.newDialogData = JSON.parse(JSON.stringify(this.dialogData));
|
|
119
159
|
},
|
|
120
160
|
// 确认按钮
|
|
121
161
|
confirmField() {
|
|
162
|
+
this.syncDialogDraft();
|
|
163
|
+
this.stopDialogSync();
|
|
122
164
|
this.$emit("show-field", this.newDialogData);
|
|
123
165
|
this.plDialogFals = false;
|
|
124
166
|
clearTimeout(this._times);
|
|
125
167
|
this.$refs.plDialog.style.width = 0 + "px";
|
|
126
|
-
this.aBox.style.display = "none";
|
|
127
168
|
this.clearNode();
|
|
128
169
|
},
|
|
129
170
|
// 重置按钮
|
|
130
171
|
reset() {
|
|
172
|
+
this.syncDialogDraft();
|
|
173
|
+
this.stopDialogSync();
|
|
131
174
|
this.$emit("reset", this.newDialogData);
|
|
132
175
|
this.plDialogFals = false;
|
|
133
176
|
clearTimeout(this._times);
|
|
134
177
|
this.$refs.plDialog.style.width = 0 + "px";
|
|
135
|
-
this.aBox.style.display = "none";
|
|
136
178
|
this.clearNode();
|
|
137
179
|
},
|
|
180
|
+
syncDialogDraft() {
|
|
181
|
+
if (!this._dialogDraft) return;
|
|
182
|
+
this._dialogDraft = mergeDialogDraft(this._dialogDraft, this.dialogData, this.newDialogData);
|
|
183
|
+
this.newDialogData = this._dialogDraft.value;
|
|
184
|
+
},
|
|
185
|
+
stopDialogSync() {
|
|
186
|
+
if (this._dialogUnwatch) this._dialogUnwatch();
|
|
187
|
+
this._dialogUnwatch = null;
|
|
188
|
+
this._dialogDraft = null;
|
|
189
|
+
},
|
|
138
190
|
// 修改字段名按钮事件
|
|
139
191
|
amendField(item, index) {
|
|
140
192
|
this.$emit("amend-field", item, index);
|
|
@@ -144,10 +196,6 @@ export default {
|
|
|
144
196
|
// 删除节点
|
|
145
197
|
let parent = this.aBox ? this.aBox.parentNode : "";
|
|
146
198
|
parent && parent.removeChild(this.aBox);
|
|
147
|
-
let doms = document.getElementsByClassName("modal-backdrop");
|
|
148
|
-
if (doms.length > 0) {
|
|
149
|
-
document.body.removeChild(doms[0]);
|
|
150
|
-
}
|
|
151
199
|
this.aBox = null;
|
|
152
200
|
},
|
|
153
201
|
|
|
@@ -199,7 +247,7 @@ export default {
|
|
|
199
247
|
}
|
|
200
248
|
});
|
|
201
249
|
// 当选择项发生变化时会触发该事件(仅在有监听者时取值,避免无监听时全表扫描)
|
|
202
|
-
if (this
|
|
250
|
+
if (hasGridListener(this, "selection-change")) {
|
|
203
251
|
const data = this.$refs.singleTable.getCheckboxRecords();
|
|
204
252
|
this.$emit("selection-change", data);
|
|
205
253
|
}
|
|
@@ -210,7 +258,7 @@ export default {
|
|
|
210
258
|
if (this.$refs.singleTable) {
|
|
211
259
|
this.$refs.singleTable.setAllCheckboxRow(checked);
|
|
212
260
|
// 当选择项发生变化时会触发该事件(仅在有监听者时取值)
|
|
213
|
-
if (this
|
|
261
|
+
if (hasGridListener(this, "selection-change")) {
|
|
214
262
|
const data = this.$refs.singleTable.getCheckboxRecords();
|
|
215
263
|
this.$emit("selection-change", data);
|
|
216
264
|
}
|
|
@@ -223,7 +271,7 @@ export default {
|
|
|
223
271
|
if (this.$refs.singleTable) {
|
|
224
272
|
this.$refs.singleTable.clearCheckboxRow();
|
|
225
273
|
// 当选择项发生变化时会触发该事件(仅在有监听者时取值)
|
|
226
|
-
if (this
|
|
274
|
+
if (hasGridListener(this, "selection-change")) {
|
|
227
275
|
const data = this.$refs.singleTable.getCheckboxRecords();
|
|
228
276
|
this.$emit("selection-change", data);
|
|
229
277
|
}
|
|
@@ -249,7 +297,8 @@ export default {
|
|
|
249
297
|
},
|
|
250
298
|
// 对 Table 进行重新布局。当 Table 或其祖先元素由隐藏切换为显示时,可能需要调用此方法
|
|
251
299
|
doLayout() {
|
|
252
|
-
this
|
|
300
|
+
const revision = this._selectedRevision || 0;
|
|
301
|
+
this.refreshSelectedAfter(this.$refs.singleTable.recalculate(), revision);
|
|
253
302
|
},
|
|
254
303
|
// 让表格滚动条回到顶部,和左侧
|
|
255
304
|
pagingScrollTopLeft(top = 0, left = 0) {
|
|
@@ -274,7 +323,8 @@ export default {
|
|
|
274
323
|
return this.$refs.singleTable.loadColumn(data);
|
|
275
324
|
},
|
|
276
325
|
refreshColumn() {
|
|
277
|
-
this
|
|
326
|
+
const revision = this._selectedRevision || 0;
|
|
327
|
+
this.refreshSelectedAfter(this.$refs.singleTable.refreshColumn(), revision);
|
|
278
328
|
},
|
|
279
329
|
// 激活编辑状态
|
|
280
330
|
setActiveRow(row) {
|
|
@@ -450,31 +500,34 @@ export default {
|
|
|
450
500
|
selectAll(params) {
|
|
451
501
|
// vxe 事件参数里的 records 是惰性 getter,仅在有监听者时才取值,避免每次全选都全表扫描
|
|
452
502
|
if (
|
|
453
|
-
this
|
|
454
|
-
this
|
|
503
|
+
hasGridListener(this, "select-all") ||
|
|
504
|
+
hasGridListener(this, "selection-change")
|
|
455
505
|
) {
|
|
456
506
|
const data =
|
|
457
507
|
params && typeof params.records === "function"
|
|
458
508
|
? params.records()
|
|
459
|
-
:
|
|
509
|
+
: params && Array.isArray(params.records)
|
|
510
|
+
? params.records : this.$refs.singleTable.getCheckboxRecords();
|
|
460
511
|
this.$emit("select-all", data);
|
|
461
512
|
// 当选择项发生变化时会触发该事件
|
|
462
513
|
this.$emit("selection-change", data);
|
|
463
514
|
}
|
|
515
|
+
bridgeStoppedClick(this, params, true);
|
|
464
516
|
},
|
|
465
517
|
// 当用户手动勾选数据行的 Checkbox 时触发的事件
|
|
466
518
|
plSelect(params) {
|
|
467
519
|
const { row, records } = params || {};
|
|
468
520
|
// vxe 事件参数里的 records 是惰性 getter,仅在有监听者时才取值,避免每次勾选都全表扫描
|
|
469
|
-
if (this
|
|
521
|
+
if (hasGridListener(this, "select") || hasGridListener(this, "selection-change")) {
|
|
470
522
|
const data =
|
|
471
523
|
typeof records === "function"
|
|
472
524
|
? records()
|
|
473
|
-
: this.$refs.singleTable.getCheckboxRecords();
|
|
525
|
+
: Array.isArray(records) ? records : this.$refs.singleTable.getCheckboxRecords();
|
|
474
526
|
this.$emit("select", data, row);
|
|
475
527
|
// 当选择项发生变化时会触发该事件
|
|
476
528
|
this.$emit("selection-change", data);
|
|
477
529
|
}
|
|
530
|
+
bridgeStoppedClick(this, params, false);
|
|
478
531
|
},
|
|
479
532
|
// 只对 type=radio 有效,当手动勾选并且值发生改变时触发的事件
|
|
480
533
|
radioChange({
|
|
@@ -485,13 +538,16 @@ export default {
|
|
|
485
538
|
columnIndex,
|
|
486
539
|
$columnIndex,
|
|
487
540
|
cell,
|
|
541
|
+
$event,
|
|
488
542
|
}) {
|
|
489
543
|
this.$emit("radio-change", row, column);
|
|
544
|
+
bridgeStoppedClick(this, { row, column, cell, $event }, false);
|
|
490
545
|
},
|
|
491
546
|
// 当表格的排序条件发生变化的时候会触发该事件
|
|
492
|
-
sortChange({ column, property, order }) {
|
|
493
|
-
let objs = { column, prop: property, order };
|
|
547
|
+
sortChange({ column, property, field, order, $event }) {
|
|
548
|
+
let objs = { column, prop: property === undefined ? field : property, order };
|
|
494
549
|
this.$emit("sort-change", objs);
|
|
550
|
+
bridgeStoppedClick(this, { column, $event }, true);
|
|
495
551
|
},
|
|
496
552
|
// 当表格的当前行发生变化的时候会触发该事件
|
|
497
553
|
currentChange({ row }) {
|
|
@@ -518,15 +574,32 @@ export default {
|
|
|
518
574
|
$columnIndex,
|
|
519
575
|
$event,
|
|
520
576
|
});
|
|
577
|
+
bridgeStoppedClick(this, { row, column, $event }, false);
|
|
521
578
|
},
|
|
522
579
|
// 当表格的筛选条件发生变化的时候会触发该事件
|
|
523
|
-
filterChange({ column, property, values, datas, filters, $event }) {
|
|
580
|
+
filterChange({ column, property, field, values, datas, filters, $event }) {
|
|
581
|
+
const supplied = typeof filters === "function" ? filters() : filters;
|
|
582
|
+
const table = this.$refs.singleTable;
|
|
583
|
+
const columns = table && table.getTableColumn ? table.getTableColumn().visibleColumn : null;
|
|
584
|
+
// The legacy wrapper reports every visible filterable column, including
|
|
585
|
+
// those with no selection. Keep the new kernel's checked-only API intact.
|
|
586
|
+
const compatibleFilters = columns ? columns.filter(item => item.filters && item.filters.length).map(item => {
|
|
587
|
+
const checked = item.filters.filter(option => option.checked);
|
|
588
|
+
const existing = (supplied || []).find(entry => entry.column === item);
|
|
589
|
+
return Object.assign({}, existing, {
|
|
590
|
+
column: item,
|
|
591
|
+
field: item.field || item.property,
|
|
592
|
+
property: item.property || item.field,
|
|
593
|
+
values: checked.map(option => option.value),
|
|
594
|
+
datas: checked.map(option => option.data),
|
|
595
|
+
});
|
|
596
|
+
}) : supplied;
|
|
524
597
|
this.$emit("filter-change", {
|
|
525
598
|
column,
|
|
526
|
-
property,
|
|
599
|
+
property: property === undefined ? field : property,
|
|
527
600
|
values,
|
|
528
601
|
datas,
|
|
529
|
-
filters,
|
|
602
|
+
filters: compatibleFilters,
|
|
530
603
|
$event,
|
|
531
604
|
});
|
|
532
605
|
},
|
|
@@ -541,6 +614,10 @@ export default {
|
|
|
541
614
|
cell,
|
|
542
615
|
$event,
|
|
543
616
|
}) {
|
|
617
|
+
// VXE dispatches this from mouseover, which also bubbles when moving
|
|
618
|
+
// between descendants. The legacy wrapper exposes mouseenter semantics.
|
|
619
|
+
const relatedTarget = $event && $event.relatedTarget;
|
|
620
|
+
if (cell && relatedTarget && relatedTarget.nodeType && cell.contains(relatedTarget)) return;
|
|
544
621
|
this.$emit("cell-mouse-enter", row, column, cell, $event);
|
|
545
622
|
},
|
|
546
623
|
// 当单元格 hover 退出时会触发该事件
|
|
@@ -567,6 +644,7 @@ export default {
|
|
|
567
644
|
cell,
|
|
568
645
|
$event,
|
|
569
646
|
}) {
|
|
647
|
+
if (repeatedClick(this, "_cellClickEvents", $event)) return;
|
|
570
648
|
this.$emit("cell-click", row, column, cell, $event);
|
|
571
649
|
// row-click 当某一行被点击时会触发该事件 row, event, column
|
|
572
650
|
// 只有当点击的单元格不是复选框才触发行事件!
|
|
@@ -603,6 +681,7 @@ export default {
|
|
|
603
681
|
columnIndex,
|
|
604
682
|
$event,
|
|
605
683
|
}) {
|
|
684
|
+
if (repeatedClick(this, "_headerClickEvents", $event)) return;
|
|
606
685
|
this.$emit("header-click", column, $event);
|
|
607
686
|
},
|
|
608
687
|
// 当某一列的表头被鼠标右键点击时触发该事件 column, $event
|
|
@@ -683,25 +762,53 @@ export default {
|
|
|
683
762
|
$columnIndex,
|
|
684
763
|
});
|
|
685
764
|
},
|
|
765
|
+
// elx-grid 扩展事件:鼠标或键盘切换当前选中单元格时触发
|
|
766
|
+
editCurrentlyActive({ row, column, cell }) {
|
|
767
|
+
this._selectedRevision = (this._selectedRevision || 0) + 1;
|
|
768
|
+
const table = this.$refs.singleTable;
|
|
769
|
+
const targetCell =
|
|
770
|
+
cell ||
|
|
771
|
+
(table && table.getCellElement
|
|
772
|
+
? table.getCellElement(row, column)
|
|
773
|
+
: null);
|
|
774
|
+
this.$emit("edit-currently-active", {
|
|
775
|
+
row,
|
|
776
|
+
column,
|
|
777
|
+
cell: targetCell,
|
|
778
|
+
});
|
|
779
|
+
},
|
|
780
|
+
// Only public wrapper refreshes participate; no global VXE hooks or
|
|
781
|
+
// private editStore access. Preserve the legacy undefined method return.
|
|
782
|
+
refreshSelectedAfter(completion, revision = this._selectedRevision || 0) {
|
|
783
|
+
Promise.resolve(completion).then(() => this.$nextTick()).then(() => {
|
|
784
|
+
if (this._isDestroyed || this._isBeingDestroyed ||
|
|
785
|
+
revision !== (this._selectedRevision || 0) ||
|
|
786
|
+
!hasGridListener(this, "edit-currently-active")) return;
|
|
787
|
+
const table = this.$refs.singleTable;
|
|
788
|
+
const selected = table && table.getSelectedCell ? table.getSelectedCell() : null;
|
|
789
|
+
if (!selected) return;
|
|
790
|
+
const cell = table.getCellElement(selected.row, selected.column);
|
|
791
|
+
if (cell) this.editCurrentlyActive(Object.assign({}, selected, { cell }));
|
|
792
|
+
}).catch(error => console.error("[UxGrid] Selected cell refresh failed", error));
|
|
793
|
+
},
|
|
686
794
|
// 当树节点展开或收起时会触发该事件
|
|
687
795
|
toggleTreeExpandEv(row) {
|
|
688
796
|
this.$emit("toggle-tree-expand", row);
|
|
797
|
+
bridgeStoppedClick(this, row, false);
|
|
689
798
|
},
|
|
690
799
|
// 键盘按下事件
|
|
691
800
|
keydown({ $event }) {
|
|
692
801
|
this.$emit("keydown", { $event });
|
|
693
802
|
},
|
|
694
|
-
// 当前被激活的单元格
|
|
695
|
-
editCurrentlyActive({ row, column, cell }) {
|
|
696
|
-
this.$emit("edit-currently-active", { row, column, cell });
|
|
697
|
-
},
|
|
698
803
|
// vxe 首次加载完数据并渲染完成后触发(此时列信息已构建完,DOM 稳定,可安全绑定第三方拖拽等)
|
|
699
804
|
initRendered(params) {
|
|
700
805
|
this.$emit("init-rendered", params);
|
|
701
806
|
},
|
|
702
807
|
// vxe 后续重新加载/刷新数据并渲染完成后触发
|
|
703
808
|
dataRendered(params) {
|
|
809
|
+
const revision = this._selectedRevision || 0;
|
|
704
810
|
this.$emit("data-rendered", params);
|
|
811
|
+
this.refreshSelectedAfter(undefined, revision);
|
|
705
812
|
},
|
|
706
813
|
},
|
|
707
814
|
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import XEUtils from "xe-utils";
|
|
2
|
+
|
|
3
|
+
// Keep the source snapshot separate from the editable draft. Only an open
|
|
4
|
+
// dialog owns this state; closed grids do not traverse dialogData.
|
|
5
|
+
export function createDialogDraft(source) {
|
|
6
|
+
return { source: source.slice(), baseline: XEUtils.clone(source, true), draft: XEUtils.clone(source, true) };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function mergeDialogDraft(previous, source, draft) {
|
|
10
|
+
const keyOf = item => {
|
|
11
|
+
for (const field of ["id", "field", "prop", "key"]) {
|
|
12
|
+
if (item[field] !== undefined && item[field] !== null) return field + ":" + item[field];
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
};
|
|
16
|
+
const matchIndices = (items, originals) => {
|
|
17
|
+
const indices = items.map(() => -1);
|
|
18
|
+
const used = new Set();
|
|
19
|
+
const assign = (index, oldIndex) => {
|
|
20
|
+
if (oldIndex >= 0 && !used.has(oldIndex)) {
|
|
21
|
+
indices[index] = oldIndex;
|
|
22
|
+
used.add(oldIndex);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
// Reserve every surviving reference before considering positional fallback:
|
|
26
|
+
// a new item inserted at index 0 must not take the old index of a later A.
|
|
27
|
+
items.forEach((item, index) => {
|
|
28
|
+
assign(index, originals.findIndex((entry, oldIndex) => entry === item && !used.has(oldIndex)));
|
|
29
|
+
});
|
|
30
|
+
items.forEach((item, index) => {
|
|
31
|
+
const key = keyOf(item);
|
|
32
|
+
if (indices[index] < 0 && key !== null) {
|
|
33
|
+
assign(index, previous.baseline.findIndex((entry, oldIndex) => keyOf(entry) === key && !used.has(oldIndex)));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
items.forEach((item, index) => {
|
|
37
|
+
if (indices[index] < 0 && keyOf(item) === null &&
|
|
38
|
+
index < previous.baseline.length && keyOf(previous.baseline[index]) === null) {
|
|
39
|
+
assign(index, index);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return indices;
|
|
43
|
+
};
|
|
44
|
+
const draftIndices = matchIndices(draft, previous.draft);
|
|
45
|
+
const sourceIndices = matchIndices(source, previous.source);
|
|
46
|
+
const incoming = source.map((item, index) => {
|
|
47
|
+
const oldIndex = sourceIndices[index];
|
|
48
|
+
const draftIndex = draftIndices.indexOf(oldIndex);
|
|
49
|
+
const value = XEUtils.clone(item, true);
|
|
50
|
+
if (oldIndex >= 0 && draftIndex >= 0) {
|
|
51
|
+
const base = previous.baseline[oldIndex];
|
|
52
|
+
const edited = draft[draftIndex];
|
|
53
|
+
// A local field edit wins a simultaneous parent change to that field.
|
|
54
|
+
new Set(Object.keys(base).concat(Object.keys(edited))).forEach(field => {
|
|
55
|
+
if (!XEUtils.isEqual(base[field], edited[field])) {
|
|
56
|
+
if (Object.prototype.hasOwnProperty.call(edited, field)) value[field] = XEUtils.clone(edited[field], true);
|
|
57
|
+
else delete value[field];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return { oldIndex, value };
|
|
62
|
+
});
|
|
63
|
+
const reordered = draftIndices.some((index, position) => index !== position);
|
|
64
|
+
let nextDraft = incoming.map(entry => entry.value);
|
|
65
|
+
if (reordered) {
|
|
66
|
+
const ordered = draftIndices.filter(index => index >= 0)
|
|
67
|
+
.map(index => incoming.find(entry => entry.oldIndex === index)).filter(Boolean);
|
|
68
|
+
const retained = new Set(ordered);
|
|
69
|
+
nextDraft = ordered.concat(incoming.filter(entry => !retained.has(entry))).map(entry => entry.value);
|
|
70
|
+
}
|
|
71
|
+
// Store draft references in source order so subsequent drag operations can
|
|
72
|
+
// still be matched even when the item does not declare a stable key.
|
|
73
|
+
return { source: source.slice(), baseline: XEUtils.clone(source, true),
|
|
74
|
+
draft: incoming.map(entry => entry.value), value: nextDraft };
|
|
75
|
+
}
|