data-diff-merge-table 1.0.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.
package/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # DataDiffMergeTable 表格对比组件 API
2
+
3
+ ## Props
4
+
5
+ | 属性名 | 类型 | 默认值 | 说明 |
6
+ |--------|------|--------|------|
7
+ | titles | Array\<String\> | `['', '']` | 左右对比表头标题 |
8
+ | leftData | Array | `[]` | 左侧原始数据 |
9
+ | rightData | Array | `[]` | 右侧原始数据 |
10
+ | primaryKeys | Array\<String\> | `[]` | 主键字段列表,用于左右数据行对齐与对比 |
11
+ | columns | Array | `[]` | 列定义,至少包含 `prop` `label` `width` |
12
+ | height | String | `"28vh"` | 左右对比表高度 |
13
+ | mergeHeight | String | `"28vh"` | 合并表高度 |
14
+ | align | String | `"center"` | 列内容对齐方式,可选:`left` / `center` / `right` |
15
+ | rowDiffBgColor | String | `"#5513137F"` | 差异/缺失行背景色 |
16
+ | diffCellTextColor | String | `"#d9001b"` | 差异单元格字体色 |
17
+ | isUseMerge | Boolean | `false` | 是否使用合并功能 |
18
+
19
+ ### columns 配置项(ColumnItem)
20
+
21
+ | 字段 | 类型 | 必填 | 说明 |
22
+ |------|------|------|------|
23
+ | prop | string | 是 | 对应数据字段名 |
24
+ | label | string | 是 | 列标题 |
25
+ | width | string \| number | 否 | 列宽 |
26
+
27
+ ## Emits
28
+
29
+ | 事件名 | 参数 | 触发时机 | 说明 |
30
+ |--------|------|----------|------|
31
+ | merge-change | Array\<object\> | 合并表数据变化时 | 返回合并表当前数据(含用户编辑) |
32
+ | selection-change | Record\<string, "left" \| "right" \| null\> | 选择状态变化时 | 返回每行选择状态映射 |
33
+
34
+ ### merge-change 数据项格式
35
+
36
+ | 字段 | 说明 |
37
+ |------|------|
38
+ | __key | 行唯一键(由 `primaryKeys` 拼接) |
39
+ | __side | 当前来源侧,`left` 或 `right` |
40
+ | ...columns.prop | 合并表实际可编辑字段值 |
41
+
42
+ ## 交互规则
43
+
44
+ - 一行数据只能选择左或右,互斥
45
+ - 选择"某侧全选"后,会锁定该侧,另一侧禁选
46
+ - 取消锁定全选后,恢复默认选中策略
47
+ - 默认选中策略:
48
+ - 仅一侧有数据,默认选有数据侧
49
+ - 两侧都有数据,默认选"数据量更多的一侧"
50
+ - 合并表主键列只读,不允许编辑
51
+ - 左/右/合并三张表纵向与横向滚动同步
52
+ - `hideSameRows=true` 时,对比区隐藏 same 行,但合并数据仍按当前选择生成
53
+
54
+ ## 使用示例
55
+
56
+ ```vue
57
+ <script setup name="TelWorkLogDown">
58
+ /**
59
+ * @author zhaoheng
60
+ * @description 对比合并组件(子组件)
61
+ */
62
+ import {ref} from "vue";
63
+ import DataDiffMergeTable from "@/views/payloadMonitor/telemetry/components/DataDiffMergeTable.vue";
64
+
65
+ /**
66
+ * @author zhaoheng
67
+ * @description 左右表头标题
68
+ */
69
+ const titles = ref(["左边数据", "右边数据"]);
70
+
71
+ /**
72
+ * @author zhaoheng
73
+ * @description 表格列配置
74
+ * label: 列名
75
+ * prop: 字段名(需与数据字段一致)
76
+ */
77
+ const columns = ref([
78
+ {label: "主键", prop: "id"},
79
+ {label: "名称", prop: "name"},
80
+ {label: "年龄", prop: "age"}
81
+ ]);
82
+
83
+ /**
84
+ * @author zhaoheng
85
+ * @description 主键字段(用于左右数据行对齐)
86
+ */
87
+ const primaryKeys = ref(["id"]);
88
+
89
+ /**
90
+ * @author zhaoheng
91
+ * @description 左侧原始数据
92
+ */
93
+ const leftData = [
94
+ {id: 0, name: "张三", age: 18},
95
+ {id: 1, name: "张三", age: 18},
96
+ {id: 2, name: "李四", age: 20},
97
+ {id: 4, name: "张三", age: 18},
98
+ {id: 5, name: "张三", age: 18}
99
+ ];
100
+
101
+ /**
102
+ * @author zhaoheng
103
+ * @description 右侧原始数据
104
+ */
105
+ const rightData = [
106
+ {id: 0, name: "张三", age: 18},
107
+ {id: 1, name: "王五", age: 22},
108
+ {id: 2, name: "张三", age: 19},
109
+ {id: 4, name: "李四", age: 18}
110
+ ];
111
+
112
+ /**
113
+ * @author zhaoheng
114
+ * @description 合并表数据变化回调
115
+ * @param {Array} val - 当前合并表最终数据(包含用户编辑结果)
116
+ */
117
+ function onMergeChange(val) {
118
+ console.log(val);
119
+ }
120
+ </script>
121
+
122
+ <template>
123
+ <div>
124
+ <!--
125
+ @author zhaoheng
126
+ @description 对比合并主组件
127
+ isUseMerge=true: 开启合并模式(复选框 + 合并表 + merge-change)
128
+ -->
129
+ <DataDiffMergeTable
130
+ :titles="titles"
131
+ :left-data="leftData"
132
+ :right-data="rightData"
133
+ :primary-keys="primaryKeys"
134
+ :columns="columns"
135
+ height="28vh"
136
+ merge-height="28vh"
137
+ align="center"
138
+ row-diff-bg-color="#5513137F"
139
+ diff-cell-text-color="#d9001b"
140
+ :isUseMerge="true"
141
+ @merge-change="onMergeChange"
142
+ />
143
+ </div>
144
+ </template>
145
+
146
+ <style scoped lang="scss">
147
+ /**
148
+ * @author zhaoheng
149
+ * @description 页面样式(当前无自定义样式)
150
+ */
151
+ </style>
package/dist/index.mjs ADDED
@@ -0,0 +1,451 @@
1
+ import { ref as y, computed as w, watch as U, onMounted as ke, onUnmounted as Me, resolveComponent as D, openBlock as m, createElementBlock as x, normalizeStyle as _e, createElementVNode as d, createVNode as v, createTextVNode as de, toDisplayString as b, Fragment as L, createCommentVNode as K, withCtx as s, createBlock as R, renderList as O, normalizeClass as I, nextTick as Se } from "vue";
2
+ const Ce = (o, A) => {
3
+ const r = o.__vccOpts || o;
4
+ for (const [_, V] of A)
5
+ r[_] = V;
6
+ return r;
7
+ }, Te = { class: "toolbar" }, Ue = { class: "count-text" }, De = { class: "diff-container-compare" }, xe = {
8
+ key: 0,
9
+ class: "diff-container-merge"
10
+ }, Re = {
11
+ __name: "DataDiffMergeTable",
12
+ props: {
13
+ titles: { type: Array, default: () => ["", ""] },
14
+ leftData: { type: Array, default: () => [] },
15
+ rightData: { type: Array, default: () => [] },
16
+ primaryKeys: { type: Array, default: () => [] },
17
+ columns: { type: Array, default: () => [] },
18
+ height: { type: String, default: "28vh" },
19
+ mergeHeight: { type: String, default: "28vh" },
20
+ align: { type: String, default: "center" },
21
+ rowDiffBgColor: { type: String, default: "rgba(85, 19, 19, 0.5)" },
22
+ diffCellTextColor: { type: String, default: "#d9001b" },
23
+ selectedRowBgColor: { type: String, default: "rgba(0, 193, 16, 0.09)" },
24
+ isUseMerge: { type: Boolean, default: !1 }
25
+ },
26
+ emits: ["merge-change", "selection-change"],
27
+ setup(o, { emit: A }) {
28
+ const r = o, _ = A, V = y(null), G = y(null), J = y(null), S = y(null), C = y(null), T = y(null), N = y(!0), u = y({}), g = y(null), k = y([]);
29
+ let $ = !1;
30
+ const he = w(() => ({
31
+ "--row-diff-bg": r.rowDiffBgColor,
32
+ "--diff-cell-text": r.diffCellTextColor,
33
+ "--row-selected-bg": r.isUseMerge ? r.selectedRowBgColor : "transparent"
34
+ })), ve = w(() => new Set(r.primaryKeys || [])), z = (e) => ve.value.has(e), W = /* @__PURE__ */ new Map();
35
+ function j(e) {
36
+ const t = String(e ?? "");
37
+ if (W.has(t)) return W.get(t);
38
+ const l = Math.max(80, t.length * 14 + 24);
39
+ return W.set(t, l), l;
40
+ }
41
+ function q(e, t = 16) {
42
+ let l = 0, n = null;
43
+ return (...i) => {
44
+ const h = Date.now(), c = t - (h - l);
45
+ c <= 0 ? (n && (clearTimeout(n), n = null), l = h, e(...i)) : n || (n = setTimeout(() => {
46
+ l = Date.now(), n = null, e(...i);
47
+ }, c));
48
+ };
49
+ }
50
+ function F(e) {
51
+ if ($) return;
52
+ const t = {
53
+ left: S.value,
54
+ right: C.value,
55
+ merge: T.value
56
+ }, l = t[e];
57
+ if (!l) return;
58
+ $ = !0;
59
+ const n = l.scrollTop, i = l.scrollLeft;
60
+ Object.entries(t).forEach(([h, c]) => {
61
+ !c || h === e || (c.scrollTop = n, c.scrollLeft = i);
62
+ }), requestAnimationFrame(() => {
63
+ $ = !1;
64
+ });
65
+ }
66
+ const Q = q(() => F("left"), 16), X = q(() => F("right"), 16), Y = q(() => F("merge"), 16);
67
+ function Z() {
68
+ S.value && S.value.removeEventListener("scroll", Q), C.value && C.value.removeEventListener("scroll", X), T.value && T.value.removeEventListener("scroll", Y);
69
+ }
70
+ function ee() {
71
+ Se(() => {
72
+ Z(), S.value = V.value?.$el?.querySelector(".el-scrollbar__wrap") || null, C.value = G.value?.$el?.querySelector(".el-scrollbar__wrap") || null, T.value = J.value?.$el?.querySelector(".el-scrollbar__wrap") || null, S.value && S.value.addEventListener("scroll", Q, { passive: !0 }), C.value && C.value.addEventListener("scroll", X, { passive: !0 }), T.value && T.value.addEventListener("scroll", Y, { passive: !0 });
73
+ });
74
+ }
75
+ const te = (e) => e ?? null, le = (e) => e ?? "-", ae = (e = {}) => r.primaryKeys.map((t) => String(e?.[t] ?? "")).join("__"), p = w(() => {
76
+ const e = new Map(r.leftData.map((n) => [ae(n), n])), t = new Map(r.rightData.map((n) => [ae(n), n]));
77
+ return [.../* @__PURE__ */ new Set([...e.keys(), ...t.keys()])].sort().map((n) => {
78
+ const i = e.get(n) ?? null, h = t.get(n) ?? null, c = /* @__PURE__ */ new Set();
79
+ for (const a of r.columns) {
80
+ const f = a.prop;
81
+ te(i?.[f]) !== te(h?.[f]) && c.add(f);
82
+ }
83
+ const P = !i || !h ? "missing" : c.size > 0 ? "diff" : "same";
84
+ return { key: n, left: i, right: h, diffProps: c, rowType: P };
85
+ });
86
+ }), B = w(
87
+ () => N.value ? p.value.filter((e) => e.rowType !== "same") : p.value
88
+ ), me = w(
89
+ () => r.leftData.length >= r.rightData.length ? "left" : "right"
90
+ );
91
+ function pe(e, t) {
92
+ return !!e?.[t];
93
+ }
94
+ function E(e) {
95
+ return e.left && e.right ? me.value : e.left ? "left" : e.right ? "right" : null;
96
+ }
97
+ const M = w(() => ({
98
+ left: p.value.filter((e) => !!e.left),
99
+ right: p.value.filter((e) => !!e.right)
100
+ })), ne = w(() => {
101
+ if (!r.isUseMerge) return { left: !1, right: !1 };
102
+ const e = M.value.left.length, t = M.value.right.length, l = M.value.left.filter((i) => u.value[i.key] === "left").length, n = M.value.right.filter((i) => u.value[i.key] === "right").length;
103
+ return {
104
+ left: e > 0 && l === e,
105
+ right: t > 0 && n === t
106
+ };
107
+ }), re = w(() => {
108
+ if (!r.isUseMerge) return { left: !1, right: !1 };
109
+ const e = M.value.left.length, t = M.value.right.length, l = M.value.left.filter((i) => u.value[i.key] === "left").length, n = M.value.right.filter((i) => u.value[i.key] === "right").length;
110
+ return {
111
+ left: l > 0 && l < e,
112
+ right: n > 0 && n < t
113
+ };
114
+ });
115
+ U(
116
+ () => r.isUseMerge,
117
+ (e) => {
118
+ if (!e) {
119
+ u.value = {}, g.value = null, k.value = [], _("selection-change", {}), _("merge-change", []);
120
+ return;
121
+ }
122
+ const t = {};
123
+ for (const l of p.value)
124
+ t[l.key] = E(l);
125
+ u.value = t;
126
+ },
127
+ { immediate: !0 }
128
+ ), U(
129
+ () => p.value,
130
+ (e) => {
131
+ if (!r.isUseMerge) return;
132
+ const t = {};
133
+ for (const l of e) {
134
+ if (g.value) {
135
+ t[l.key] = l[g.value] ? g.value : null;
136
+ continue;
137
+ }
138
+ const n = u.value[l.key];
139
+ n === "left" && l.left ? t[l.key] = "left" : n === "right" && l.right ? t[l.key] = "right" : t[l.key] = E(l);
140
+ }
141
+ u.value = t;
142
+ },
143
+ { immediate: !0 }
144
+ );
145
+ const ie = w(() => {
146
+ if (!r.isUseMerge) return [];
147
+ const e = [];
148
+ for (const t of p.value) {
149
+ const l = u.value[t.key];
150
+ if (!l || !t[l]) continue;
151
+ const n = {};
152
+ r.columns.forEach((i) => {
153
+ n[i.prop] = t[l]?.[i.prop] ?? null;
154
+ }), e.push({
155
+ __key: t.key,
156
+ __side: l,
157
+ ...n
158
+ });
159
+ }
160
+ return e;
161
+ });
162
+ U(
163
+ [() => ie.value, () => r.columns, () => r.isUseMerge],
164
+ () => {
165
+ if (!r.isUseMerge) {
166
+ k.value = [];
167
+ return;
168
+ }
169
+ const e = new Map(k.value.map((l) => [l.__key, l])), t = [];
170
+ for (const l of ie.value) {
171
+ const n = e.get(l.__key);
172
+ n && n.__side === l.__side ? t.push(n) : t.push({ ...l });
173
+ }
174
+ k.value = t;
175
+ },
176
+ { deep: !0, immediate: !0 }
177
+ ), U(
178
+ () => k.value,
179
+ (e) => {
180
+ r.isUseMerge && _("merge-change", e);
181
+ },
182
+ { deep: !0, immediate: !0 }
183
+ ), U(
184
+ () => u.value,
185
+ (e) => {
186
+ r.isUseMerge && _("selection-change", e);
187
+ },
188
+ { deep: !0, immediate: !0 }
189
+ );
190
+ function oe(e, t) {
191
+ return r.isUseMerge ? u.value[e.key] === t : !1;
192
+ }
193
+ function H(e, t) {
194
+ return !r.isUseMerge || !pe(e, t) ? !0 : !!(g.value && g.value !== t);
195
+ }
196
+ function se(e, t, l) {
197
+ if (r.isUseMerge && !H(e, t)) {
198
+ if (g.value === t && !l) {
199
+ u.value[e.key] = t;
200
+ return;
201
+ }
202
+ if (l) {
203
+ u.value[e.key] = t;
204
+ return;
205
+ }
206
+ u.value[e.key] = E(e);
207
+ }
208
+ }
209
+ function ue(e, t) {
210
+ if (r.isUseMerge) {
211
+ if (t) {
212
+ const l = {};
213
+ for (const n of p.value)
214
+ l[n.key] = n[e] ? e : null;
215
+ u.value = l, g.value = e;
216
+ return;
217
+ }
218
+ if (g.value === e) {
219
+ g.value = null;
220
+ const l = {};
221
+ for (const n of p.value)
222
+ l[n.key] = E(n);
223
+ u.value = l;
224
+ }
225
+ }
226
+ }
227
+ function fe(e) {
228
+ return e.rowType === "missing" ? "row-missing" : e.rowType === "diff" ? "row-diff" : "";
229
+ }
230
+ const ye = ({ row: e }) => {
231
+ const t = fe(e), l = r.isUseMerge && u.value[e.key] === "left" ? "row-selected" : "";
232
+ return [t, l].filter(Boolean).join(" ");
233
+ }, be = ({ row: e }) => {
234
+ const t = fe(e), l = r.isUseMerge && u.value[e.key] === "right" ? "row-selected" : "";
235
+ return [t, l].filter(Boolean).join(" ");
236
+ }, ce = (e, t) => e.diffProps.has(t) ? "diff-cell" : "";
237
+ return ke(ee), U(
238
+ [() => r.columns, () => B.value.length, () => k.value.length, () => r.height, () => r.mergeHeight, () => r.isUseMerge],
239
+ ee,
240
+ { deep: !0, immediate: !0 }
241
+ ), Me(Z), (e, t) => {
242
+ const l = D("el-switch"), n = D("el-checkbox"), i = D("el-table-column"), h = D("el-table"), c = D("el-card"), P = D("el-input");
243
+ return m(), x("div", {
244
+ class: "diff-container-wrap",
245
+ style: _e(he.value)
246
+ }, [
247
+ d("div", Te, [
248
+ v(l, {
249
+ modelValue: N.value,
250
+ "onUpdate:modelValue": t[0] || (t[0] = (a) => N.value = a),
251
+ "active-text": "过滤相同行",
252
+ "inactive-text": "显示全部"
253
+ }, null, 8, ["modelValue"]),
254
+ d("span", Ue, [
255
+ de(" 共 " + b(p.value.length) + " 行,当前显示 " + b(B.value.length) + " 行 ", 1),
256
+ o.isUseMerge ? (m(), x(L, { key: 0 }, [
257
+ de(",合并 " + b(k.value.length) + " 行", 1)
258
+ ], 64)) : K("", !0)
259
+ ])
260
+ ]),
261
+ d("div", De, [
262
+ v(c, { class: "compare-card" }, {
263
+ header: s(() => [
264
+ d("div", null, [
265
+ d("span", null, b(o.titles[0]), 1)
266
+ ])
267
+ ]),
268
+ default: s(() => [
269
+ v(h, {
270
+ ref_key: "leftTableRef",
271
+ ref: V,
272
+ class: "left-table",
273
+ data: B.value,
274
+ border: "",
275
+ "row-class-name": ye,
276
+ height: o.height
277
+ }, {
278
+ default: s(() => [
279
+ o.isUseMerge ? (m(), R(i, {
280
+ key: 0,
281
+ width: "50",
282
+ align: o.align
283
+ }, {
284
+ header: s(() => [
285
+ v(n, {
286
+ "model-value": ne.value.left,
287
+ indeterminate: re.value.left,
288
+ disabled: g.value === "right",
289
+ onChange: t[1] || (t[1] = (a) => ue("left", a))
290
+ }, null, 8, ["model-value", "indeterminate", "disabled"])
291
+ ]),
292
+ default: s(({ row: a }) => [
293
+ v(n, {
294
+ "model-value": oe(a, "left"),
295
+ disabled: H(a, "left"),
296
+ onChange: (f) => se(a, "left", f)
297
+ }, null, 8, ["model-value", "disabled", "onChange"])
298
+ ]),
299
+ _: 1
300
+ }, 8, ["align"])) : K("", !0),
301
+ (m(!0), x(L, null, O(o.columns, (a) => (m(), R(i, {
302
+ key: `left-${a.prop}`,
303
+ prop: a.prop,
304
+ label: a.label,
305
+ width: a.width,
306
+ "min-width": a.width ? void 0 : j(a.label),
307
+ align: o.align,
308
+ "show-overflow-tooltip": ""
309
+ }, {
310
+ header: s(() => [
311
+ d("span", null, b(a.label), 1)
312
+ ]),
313
+ default: s(({ row: f }) => [
314
+ d("span", {
315
+ class: I(ce(f, a.prop))
316
+ }, b(le(f.left?.[a.prop])), 3)
317
+ ]),
318
+ _: 2
319
+ }, 1032, ["prop", "label", "width", "min-width", "align"]))), 128))
320
+ ]),
321
+ _: 1
322
+ }, 8, ["data", "height"])
323
+ ]),
324
+ _: 1
325
+ }),
326
+ v(c, { class: "compare-card" }, {
327
+ header: s(() => [
328
+ d("div", null, [
329
+ d("span", null, b(o.titles[1]), 1)
330
+ ])
331
+ ]),
332
+ default: s(() => [
333
+ v(h, {
334
+ ref_key: "rightTableRef",
335
+ ref: G,
336
+ class: "right-table",
337
+ data: B.value,
338
+ border: "",
339
+ "row-class-name": be,
340
+ height: o.height
341
+ }, {
342
+ default: s(() => [
343
+ o.isUseMerge ? (m(), R(i, {
344
+ key: 0,
345
+ width: "50",
346
+ align: o.align
347
+ }, {
348
+ header: s(() => [
349
+ v(n, {
350
+ "model-value": ne.value.right,
351
+ indeterminate: re.value.right,
352
+ disabled: g.value === "left",
353
+ onChange: t[2] || (t[2] = (a) => ue("right", a))
354
+ }, null, 8, ["model-value", "indeterminate", "disabled"])
355
+ ]),
356
+ default: s(({ row: a }) => [
357
+ v(n, {
358
+ "model-value": oe(a, "right"),
359
+ disabled: H(a, "right"),
360
+ onChange: (f) => se(a, "right", f)
361
+ }, null, 8, ["model-value", "disabled", "onChange"])
362
+ ]),
363
+ _: 1
364
+ }, 8, ["align"])) : K("", !0),
365
+ (m(!0), x(L, null, O(o.columns, (a) => (m(), R(i, {
366
+ key: `right-${a.prop}`,
367
+ prop: a.prop,
368
+ label: a.label,
369
+ width: a.width,
370
+ "min-width": a.width ? void 0 : j(a.label),
371
+ align: o.align,
372
+ "show-overflow-tooltip": ""
373
+ }, {
374
+ header: s(() => [
375
+ d("span", null, b(a.label), 1)
376
+ ]),
377
+ default: s(({ row: f }) => [
378
+ d("span", {
379
+ class: I(ce(f, a.prop))
380
+ }, b(le(f.right?.[a.prop])), 3)
381
+ ]),
382
+ _: 2
383
+ }, 1032, ["prop", "label", "width", "min-width", "align"]))), 128))
384
+ ]),
385
+ _: 1
386
+ }, 8, ["data", "height"])
387
+ ]),
388
+ _: 1
389
+ })
390
+ ]),
391
+ o.isUseMerge ? (m(), x("div", xe, [
392
+ v(c, { class: "merge-card" }, {
393
+ header: s(() => [...t[3] || (t[3] = [
394
+ d("div", null, [
395
+ d("span", null, "合并数据")
396
+ ], -1)
397
+ ])]),
398
+ default: s(() => [
399
+ v(h, {
400
+ ref_key: "mergeTableRef",
401
+ ref: J,
402
+ class: "merge-table",
403
+ data: k.value,
404
+ border: "",
405
+ height: o.mergeHeight,
406
+ "row-key": "__key"
407
+ }, {
408
+ default: s(() => [
409
+ (m(!0), x(L, null, O(o.columns, (a) => (m(), R(i, {
410
+ key: `merge-${a.prop}`,
411
+ prop: a.prop,
412
+ label: a.label,
413
+ width: a.width,
414
+ "min-width": a.width ? void 0 : j(a.label),
415
+ align: o.align,
416
+ "show-overflow-tooltip": ""
417
+ }, {
418
+ header: s(() => [
419
+ d("span", null, b(a.label), 1)
420
+ ]),
421
+ default: s(({ row: f }) => [
422
+ v(P, {
423
+ modelValue: f[a.prop],
424
+ "onUpdate:modelValue": (we) => f[a.prop] = we,
425
+ size: "small",
426
+ clearable: !z(a.prop),
427
+ disabled: z(a.prop),
428
+ class: I({ "readonly-input": z(a.prop) })
429
+ }, null, 8, ["modelValue", "onUpdate:modelValue", "clearable", "disabled", "class"])
430
+ ]),
431
+ _: 2
432
+ }, 1032, ["prop", "label", "width", "min-width", "align"]))), 128))
433
+ ]),
434
+ _: 1
435
+ }, 8, ["data", "height"])
436
+ ]),
437
+ _: 1
438
+ })
439
+ ])) : K("", !0)
440
+ ], 4);
441
+ };
442
+ }
443
+ }, ge = /* @__PURE__ */ Ce(Re, [["__scopeId", "data-v-11b7a8dc"]]), Be = {
444
+ install(o) {
445
+ o.component("DataDiffMergeTable", ge), o.component("Data-Diff-MergeTable", ge);
446
+ }
447
+ };
448
+ export {
449
+ ge as DataDiffMergeTable,
450
+ Be as default
451
+ };
@@ -0,0 +1 @@
1
+ (function(m,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(m=typeof globalThis<"u"?globalThis:m||self,e(m.DataDiffMergeTable={},m.Vue))})(this,(function(m,e){"use strict";const ee=(s,D)=>{const o=s.__vccOpts||s;for(const[w,M]of D)o[w]=M;return o},te={class:"toolbar"},le={class:"count-text"},ne={class:"diff-container-compare"},ae={key:0,class:"diff-container-merge"},x=ee({__name:"DataDiffMergeTable",props:{titles:{type:Array,default:()=>["",""]},leftData:{type:Array,default:()=>[]},rightData:{type:Array,default:()=>[]},primaryKeys:{type:Array,default:()=>[]},columns:{type:Array,default:()=>[]},height:{type:String,default:"28vh"},mergeHeight:{type:String,default:"28vh"},align:{type:String,default:"center"},rowDiffBgColor:{type:String,default:"rgba(85, 19, 19, 0.5)"},diffCellTextColor:{type:String,default:"#d9001b"},selectedRowBgColor:{type:String,default:"rgba(0, 193, 16, 0.09)"},isUseMerge:{type:Boolean,default:!1}},emits:["merge-change","selection-change"],setup(s,{emit:D}){const o=s,w=D,M=e.ref(null),K=e.ref(null),z=e.ref(null),b=e.ref(null),k=e.ref(null),C=e.ref(null),_=e.ref(!0),c=e.ref({}),g=e.ref(null),p=e.ref([]);let N=!1;const oe=e.computed(()=>({"--row-diff-bg":o.rowDiffBgColor,"--diff-cell-text":o.diffCellTextColor,"--row-selected-bg":o.isUseMerge?o.selectedRowBgColor:"transparent"})),ie=e.computed(()=>new Set(o.primaryKeys||[])),T=t=>ie.value.has(t),B=new Map;function E(t){const l=String(t??"");if(B.has(l))return B.get(l);const n=Math.max(80,l.length*14+24);return B.set(l,n),n}function U(t,l=16){let n=0,r=null;return(...i)=>{const u=Date.now(),d=l-(u-n);d<=0?(r&&(clearTimeout(r),r=null),n=u,t(...i)):r||(r=setTimeout(()=>{n=Date.now(),r=null,t(...i)},d))}}function R(t){if(N)return;const l={left:b.value,right:k.value,merge:C.value},n=l[t];if(!n)return;N=!0;const r=n.scrollTop,i=n.scrollLeft;Object.entries(l).forEach(([u,d])=>{!d||u===t||(d.scrollTop=r,d.scrollLeft=i)}),requestAnimationFrame(()=>{N=!1})}const A=U(()=>R("left"),16),F=U(()=>R("right"),16),j=U(()=>R("merge"),16);function $(){b.value&&b.value.removeEventListener("scroll",A),k.value&&k.value.removeEventListener("scroll",F),C.value&&C.value.removeEventListener("scroll",j)}function q(){e.nextTick(()=>{$(),b.value=M.value?.$el?.querySelector(".el-scrollbar__wrap")||null,k.value=K.value?.$el?.querySelector(".el-scrollbar__wrap")||null,C.value=z.value?.$el?.querySelector(".el-scrollbar__wrap")||null,b.value&&b.value.addEventListener("scroll",A,{passive:!0}),k.value&&k.value.addEventListener("scroll",F,{passive:!0}),C.value&&C.value.addEventListener("scroll",j,{passive:!0})})}const W=t=>t??null,P=t=>t??"-",H=(t={})=>o.primaryKeys.map(l=>String(t?.[l]??"")).join("__"),h=e.computed(()=>{const t=new Map(o.leftData.map(r=>[H(r),r])),l=new Map(o.rightData.map(r=>[H(r),r]));return[...new Set([...t.keys(),...l.keys()])].sort().map(r=>{const i=t.get(r)??null,u=l.get(r)??null,d=new Set;for(const a of o.columns){const f=a.prop;W(i?.[f])!==W(u?.[f])&&d.add(f)}const L=!i||!u?"missing":d.size>0?"diff":"same";return{key:r,left:i,right:u,diffProps:d,rowType:L}})}),S=e.computed(()=>_.value?h.value.filter(t=>t.rowType!=="same"):h.value),se=e.computed(()=>o.leftData.length>=o.rightData.length?"left":"right");function ce(t,l){return!!t?.[l]}function V(t){return t.left&&t.right?se.value:t.left?"left":t.right?"right":null}const y=e.computed(()=>({left:h.value.filter(t=>!!t.left),right:h.value.filter(t=>!!t.right)})),O=e.computed(()=>{if(!o.isUseMerge)return{left:!1,right:!1};const t=y.value.left.length,l=y.value.right.length,n=y.value.left.filter(i=>c.value[i.key]==="left").length,r=y.value.right.filter(i=>c.value[i.key]==="right").length;return{left:t>0&&n===t,right:l>0&&r===l}}),I=e.computed(()=>{if(!o.isUseMerge)return{left:!1,right:!1};const t=y.value.left.length,l=y.value.right.length,n=y.value.left.filter(i=>c.value[i.key]==="left").length,r=y.value.right.filter(i=>c.value[i.key]==="right").length;return{left:n>0&&n<t,right:r>0&&r<l}});e.watch(()=>o.isUseMerge,t=>{if(!t){c.value={},g.value=null,p.value=[],w("selection-change",{}),w("merge-change",[]);return}const l={};for(const n of h.value)l[n.key]=V(n);c.value=l},{immediate:!0}),e.watch(()=>h.value,t=>{if(!o.isUseMerge)return;const l={};for(const n of t){if(g.value){l[n.key]=n[g.value]?g.value:null;continue}const r=c.value[n.key];r==="left"&&n.left?l[n.key]="left":r==="right"&&n.right?l[n.key]="right":l[n.key]=V(n)}c.value=l},{immediate:!0});const G=e.computed(()=>{if(!o.isUseMerge)return[];const t=[];for(const l of h.value){const n=c.value[l.key];if(!n||!l[n])continue;const r={};o.columns.forEach(i=>{r[i.prop]=l[n]?.[i.prop]??null}),t.push({__key:l.key,__side:n,...r})}return t});e.watch([()=>G.value,()=>o.columns,()=>o.isUseMerge],()=>{if(!o.isUseMerge){p.value=[];return}const t=new Map(p.value.map(n=>[n.__key,n])),l=[];for(const n of G.value){const r=t.get(n.__key);r&&r.__side===n.__side?l.push(r):l.push({...n})}p.value=l},{deep:!0,immediate:!0}),e.watch(()=>p.value,t=>{o.isUseMerge&&w("merge-change",t)},{deep:!0,immediate:!0}),e.watch(()=>c.value,t=>{o.isUseMerge&&w("selection-change",t)},{deep:!0,immediate:!0});function J(t,l){return o.isUseMerge?c.value[t.key]===l:!1}function v(t,l){return!o.isUseMerge||!ce(t,l)?!0:!!(g.value&&g.value!==l)}function Q(t,l,n){if(o.isUseMerge&&!v(t,l)){if(g.value===l&&!n){c.value[t.key]=l;return}if(n){c.value[t.key]=l;return}c.value[t.key]=V(t)}}function X(t,l){if(o.isUseMerge){if(l){const n={};for(const r of h.value)n[r.key]=r[t]?t:null;c.value=n,g.value=t;return}if(g.value===t){g.value=null;const n={};for(const r of h.value)n[r.key]=V(r);c.value=n}}}function Y(t){return t.rowType==="missing"?"row-missing":t.rowType==="diff"?"row-diff":""}const fe=({row:t})=>{const l=Y(t),n=o.isUseMerge&&c.value[t.key]==="left"?"row-selected":"";return[l,n].filter(Boolean).join(" ")},de=({row:t})=>{const l=Y(t),n=o.isUseMerge&&c.value[t.key]==="right"?"row-selected":"";return[l,n].filter(Boolean).join(" ")},Z=(t,l)=>t.diffProps.has(l)?"diff-cell":"";return e.onMounted(q),e.watch([()=>o.columns,()=>S.value.length,()=>p.value.length,()=>o.height,()=>o.mergeHeight,()=>o.isUseMerge],q,{deep:!0,immediate:!0}),e.onUnmounted($),(t,l)=>{const n=e.resolveComponent("el-switch"),r=e.resolveComponent("el-checkbox"),i=e.resolveComponent("el-table-column"),u=e.resolveComponent("el-table"),d=e.resolveComponent("el-card"),L=e.resolveComponent("el-input");return e.openBlock(),e.createElementBlock("div",{class:"diff-container-wrap",style:e.normalizeStyle(oe.value)},[e.createElementVNode("div",te,[e.createVNode(n,{modelValue:_.value,"onUpdate:modelValue":l[0]||(l[0]=a=>_.value=a),"active-text":"过滤相同行","inactive-text":"显示全部"},null,8,["modelValue"]),e.createElementVNode("span",le,[e.createTextVNode(" 共 "+e.toDisplayString(h.value.length)+" 行,当前显示 "+e.toDisplayString(S.value.length)+" 行 ",1),s.isUseMerge?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createTextVNode(",合并 "+e.toDisplayString(p.value.length)+" 行",1)],64)):e.createCommentVNode("",!0)])]),e.createElementVNode("div",ne,[e.createVNode(d,{class:"compare-card"},{header:e.withCtx(()=>[e.createElementVNode("div",null,[e.createElementVNode("span",null,e.toDisplayString(s.titles[0]),1)])]),default:e.withCtx(()=>[e.createVNode(u,{ref_key:"leftTableRef",ref:M,class:"left-table",data:S.value,border:"","row-class-name":fe,height:s.height},{default:e.withCtx(()=>[s.isUseMerge?(e.openBlock(),e.createBlock(i,{key:0,width:"50",align:s.align},{header:e.withCtx(()=>[e.createVNode(r,{"model-value":O.value.left,indeterminate:I.value.left,disabled:g.value==="right",onChange:l[1]||(l[1]=a=>X("left",a))},null,8,["model-value","indeterminate","disabled"])]),default:e.withCtx(({row:a})=>[e.createVNode(r,{"model-value":J(a,"left"),disabled:v(a,"left"),onChange:f=>Q(a,"left",f)},null,8,["model-value","disabled","onChange"])]),_:1},8,["align"])):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(s.columns,a=>(e.openBlock(),e.createBlock(i,{key:`left-${a.prop}`,prop:a.prop,label:a.label,width:a.width,"min-width":a.width?void 0:E(a.label),align:s.align,"show-overflow-tooltip":""},{header:e.withCtx(()=>[e.createElementVNode("span",null,e.toDisplayString(a.label),1)]),default:e.withCtx(({row:f})=>[e.createElementVNode("span",{class:e.normalizeClass(Z(f,a.prop))},e.toDisplayString(P(f.left?.[a.prop])),3)]),_:2},1032,["prop","label","width","min-width","align"]))),128))]),_:1},8,["data","height"])]),_:1}),e.createVNode(d,{class:"compare-card"},{header:e.withCtx(()=>[e.createElementVNode("div",null,[e.createElementVNode("span",null,e.toDisplayString(s.titles[1]),1)])]),default:e.withCtx(()=>[e.createVNode(u,{ref_key:"rightTableRef",ref:K,class:"right-table",data:S.value,border:"","row-class-name":de,height:s.height},{default:e.withCtx(()=>[s.isUseMerge?(e.openBlock(),e.createBlock(i,{key:0,width:"50",align:s.align},{header:e.withCtx(()=>[e.createVNode(r,{"model-value":O.value.right,indeterminate:I.value.right,disabled:g.value==="left",onChange:l[2]||(l[2]=a=>X("right",a))},null,8,["model-value","indeterminate","disabled"])]),default:e.withCtx(({row:a})=>[e.createVNode(r,{"model-value":J(a,"right"),disabled:v(a,"right"),onChange:f=>Q(a,"right",f)},null,8,["model-value","disabled","onChange"])]),_:1},8,["align"])):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(s.columns,a=>(e.openBlock(),e.createBlock(i,{key:`right-${a.prop}`,prop:a.prop,label:a.label,width:a.width,"min-width":a.width?void 0:E(a.label),align:s.align,"show-overflow-tooltip":""},{header:e.withCtx(()=>[e.createElementVNode("span",null,e.toDisplayString(a.label),1)]),default:e.withCtx(({row:f})=>[e.createElementVNode("span",{class:e.normalizeClass(Z(f,a.prop))},e.toDisplayString(P(f.right?.[a.prop])),3)]),_:2},1032,["prop","label","width","min-width","align"]))),128))]),_:1},8,["data","height"])]),_:1})]),s.isUseMerge?(e.openBlock(),e.createElementBlock("div",ae,[e.createVNode(d,{class:"merge-card"},{header:e.withCtx(()=>[...l[3]||(l[3]=[e.createElementVNode("div",null,[e.createElementVNode("span",null,"合并数据")],-1)])]),default:e.withCtx(()=>[e.createVNode(u,{ref_key:"mergeTableRef",ref:z,class:"merge-table",data:p.value,border:"",height:s.mergeHeight,"row-key":"__key"},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(s.columns,a=>(e.openBlock(),e.createBlock(i,{key:`merge-${a.prop}`,prop:a.prop,label:a.label,width:a.width,"min-width":a.width?void 0:E(a.label),align:s.align,"show-overflow-tooltip":""},{header:e.withCtx(()=>[e.createElementVNode("span",null,e.toDisplayString(a.label),1)]),default:e.withCtx(({row:f})=>[e.createVNode(L,{modelValue:f[a.prop],"onUpdate:modelValue":ge=>f[a.prop]=ge,size:"small",clearable:!T(a.prop),disabled:T(a.prop),class:e.normalizeClass({"readonly-input":T(a.prop)})},null,8,["modelValue","onUpdate:modelValue","clearable","disabled","class"])]),_:2},1032,["prop","label","width","min-width","align"]))),128))]),_:1},8,["data","height"])]),_:1})])):e.createCommentVNode("",!0)],4)}}},[["__scopeId","data-v-11b7a8dc"]]),re={install(s){s.component("DataDiffMergeTable",x),s.component("Data-Diff-MergeTable",x)}};m.DataDiffMergeTable=x,m.default=re,Object.defineProperties(m,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .diff-container-wrap[data-v-11b7a8dc]{display:flex;flex-direction:column;gap:10px;width:100%}.toolbar[data-v-11b7a8dc]{display:flex;align-items:center;gap:12px}.count-text[data-v-11b7a8dc]{color:#909399;font-size:12px}.diff-container-compare[data-v-11b7a8dc]{display:flex;gap:10px;width:100%}.compare-card[data-v-11b7a8dc]{flex:1 1 0;min-width:0}.diff-container-merge[data-v-11b7a8dc],.merge-card[data-v-11b7a8dc]{width:100%}@media(max-width:960px){.diff-container-compare[data-v-11b7a8dc]{flex-direction:column}.compare-card[data-v-11b7a8dc]{width:100%}}[data-v-11b7a8dc] .el-table .row-diff>td.el-table__cell{background:var(--row-diff-bg)!important}[data-v-11b7a8dc] .el-table .row-missing>td.el-table__cell{background:var(--row-diff-bg)!important}[data-v-11b7a8dc] .el-table .row-selected>td.el-table__cell{background:var(--row-selected-bg)!important}.diff-cell[data-v-11b7a8dc]{color:var(--diff-cell-text);font-weight:700}
package/dist/vite.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "data-diff-merge-table",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "vite",
7
+ "build": "vite build",
8
+ "build:lib": "vite build --mode lib",
9
+ "preview": "vite preview"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "main": "./dist/index.umd.cjs",
15
+ "module": "./dist/index.mjs",
16
+ "style": "./dist/style.css",
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.umd.cjs"
21
+ },
22
+ "./style.css": "./dist/style.css"
23
+ },
24
+ "peerDependencies": {
25
+ "vue": "^3.3.0",
26
+ "element-plus": "^2.0.0",
27
+ "@element-plus/icons-vue": "^2.0.0",
28
+ "gridstack": "^12.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@element-plus/icons-vue": "2.3.1",
32
+ "element-plus": "^2.10.3",
33
+ "gridstack": "^12.2.2",
34
+ "vue": "^3.5.25",
35
+ "@vitejs/plugin-vue": "^6.0.2",
36
+ "sass-embedded": "^1.97.3",
37
+ "vite": "^7.3.1"
38
+ }
39
+ }