vue2-excel-grid 1.7.0 → 1.7.2
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 +2 -0
- package/dist/vue2-excel-grid.esm.js +61 -192
- package/dist/vue2-excel-grid.umd.js +2 -2
- package/package.json +1 -1
- package/src/components/EgLocalSyncModal.vue +27 -62
- package/src/components/ExcelGrid.vue +19 -42
- package/src/utils/i18n.js +0 -4
package/package.json
CHANGED
|
@@ -13,20 +13,17 @@
|
|
|
13
13
|
<span>{{ t.localSyncSavedAt }}: {{ savedAtText }}</span>
|
|
14
14
|
<span>{{ snapshot.data.length }} {{ t.localSyncRows }}</span>
|
|
15
15
|
</div>
|
|
16
|
-
<div class="eg-lsm-
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
</tbody>
|
|
28
|
-
</table>
|
|
29
|
-
<div v-if="hiddenRowCount > 0" class="eg-lsm-more">{{ moreRowsText }}</div>
|
|
16
|
+
<div class="eg-lsm-grid-wrap">
|
|
17
|
+
<component
|
|
18
|
+
:is="gridOptions"
|
|
19
|
+
:data="snapshot.data"
|
|
20
|
+
:columns="columns"
|
|
21
|
+
:height="360"
|
|
22
|
+
:locale="locale"
|
|
23
|
+
:theme="theme"
|
|
24
|
+
locked
|
|
25
|
+
:toolbar="false"
|
|
26
|
+
/>
|
|
30
27
|
</div>
|
|
31
28
|
</template>
|
|
32
29
|
</div>
|
|
@@ -69,18 +66,27 @@
|
|
|
69
66
|
// and lets the host Restore it back into the grid or delete it. Not exported
|
|
70
67
|
// from src/index.js (same "internal-only" convention as EgDatePicker.vue /
|
|
71
68
|
// EgCheckbox.vue) — purpose-built for ExcelGrid.vue, not meant for standalone use.
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
//
|
|
70
|
+
// The preview itself is a real, nested ExcelGrid instance (locked/read-only,
|
|
71
|
+
// no toolbar) rather than a hand-rolled <table> — this gets column
|
|
72
|
+
// formatting/select-labels/date-formatting/virtual scrolling for free and
|
|
73
|
+
// correctly resolves function-based col.options against the preview grid's
|
|
74
|
+
// OWN row indices (impossible for a detached snapshot row via the live
|
|
75
|
+
// grid's own resolver). `gridOptions` is ExcelGrid.vue's own `$options`,
|
|
76
|
+
// passed down by the parent instance instead of importing ExcelGrid.vue
|
|
77
|
+
// here directly — that import would be circular (ExcelGrid.vue -> this file
|
|
78
|
+
// -> ExcelGrid.vue).
|
|
74
79
|
import { getMessages } from '../utils/i18n.js'
|
|
75
80
|
|
|
76
81
|
export default {
|
|
77
82
|
name: 'EgLocalSyncModal',
|
|
78
83
|
props: {
|
|
79
84
|
visible: { type: Boolean, default: false },
|
|
85
|
+
gridOptions: { type: Object, required: true },
|
|
80
86
|
columns: { type: Array, default: () => [] },
|
|
81
87
|
snapshot: { type: Object, default: null }, // { data, updatedAt } | null
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
locale: { type: String, default: 'en' },
|
|
89
|
+
theme: { type: String, default: 'excel' }
|
|
84
90
|
},
|
|
85
91
|
data() {
|
|
86
92
|
return { confirmingClear: false }
|
|
@@ -90,17 +96,6 @@ export default {
|
|
|
90
96
|
savedAtText() {
|
|
91
97
|
if (!this.snapshot) return ''
|
|
92
98
|
return new Date(this.snapshot.updatedAt).toLocaleString()
|
|
93
|
-
},
|
|
94
|
-
previewRows() {
|
|
95
|
-
if (!this.snapshot) return []
|
|
96
|
-
return this.snapshot.data.slice(0, PREVIEW_ROW_LIMIT)
|
|
97
|
-
},
|
|
98
|
-
hiddenRowCount() {
|
|
99
|
-
if (!this.snapshot) return 0
|
|
100
|
-
return Math.max(0, this.snapshot.data.length - PREVIEW_ROW_LIMIT)
|
|
101
|
-
},
|
|
102
|
-
moreRowsText() {
|
|
103
|
-
return (this.t.localSyncMoreRows || '').replace('{n}', this.hiddenRowCount)
|
|
104
99
|
}
|
|
105
100
|
},
|
|
106
101
|
watch: {
|
|
@@ -133,7 +128,7 @@ export default {
|
|
|
133
128
|
border: 1px solid var(--eg-color-border-cell, var(--eg-color-border-cell-default));
|
|
134
129
|
border-radius: var(--eg-radius, var(--eg-radius-default));
|
|
135
130
|
box-shadow: var(--eg-shadow-dialog, var(--eg-shadow-dialog-default));
|
|
136
|
-
width: min(
|
|
131
|
+
width: min(1200px, 94vw);
|
|
137
132
|
max-height: 82vh;
|
|
138
133
|
display: flex;
|
|
139
134
|
flex-direction: column;
|
|
@@ -184,40 +179,10 @@ export default {
|
|
|
184
179
|
color: var(--eg-color-text-secondary, var(--eg-color-text-secondary-default));
|
|
185
180
|
margin-bottom: 10px;
|
|
186
181
|
}
|
|
187
|
-
.eg-lsm-
|
|
182
|
+
.eg-lsm-grid-wrap {
|
|
188
183
|
border: 1px solid var(--eg-color-border-cell, var(--eg-color-border-cell-default));
|
|
189
184
|
border-radius: var(--eg-radius, var(--eg-radius-default));
|
|
190
|
-
overflow:
|
|
191
|
-
max-height: 45vh;
|
|
192
|
-
}
|
|
193
|
-
.eg-lsm-table {
|
|
194
|
-
width: 100%;
|
|
195
|
-
border-collapse: collapse;
|
|
196
|
-
font-size: var(--eg-font-size, var(--eg-font-size-default));
|
|
197
|
-
color: var(--eg-color-text, var(--eg-color-text-default));
|
|
198
|
-
}
|
|
199
|
-
.eg-lsm-table th,
|
|
200
|
-
.eg-lsm-table td {
|
|
201
|
-
padding: 6px 10px;
|
|
202
|
-
border-bottom: 1px solid var(--eg-color-border-cell, var(--eg-color-border-cell-default));
|
|
203
|
-
text-align: left;
|
|
204
|
-
white-space: nowrap;
|
|
205
|
-
}
|
|
206
|
-
.eg-lsm-table th {
|
|
207
|
-
position: sticky;
|
|
208
|
-
top: 0;
|
|
209
|
-
background: var(--eg-color-header-bg, var(--eg-color-header-bg-default));
|
|
210
|
-
font-weight: 600;
|
|
211
|
-
z-index: 1;
|
|
212
|
-
}
|
|
213
|
-
.eg-lsm-table tbody tr:last-child td {
|
|
214
|
-
border-bottom: none;
|
|
215
|
-
}
|
|
216
|
-
.eg-lsm-more {
|
|
217
|
-
padding: 8px 10px;
|
|
218
|
-
font-size: 12px;
|
|
219
|
-
color: var(--eg-color-text-muted, var(--eg-color-text-muted-default));
|
|
220
|
-
text-align: center;
|
|
185
|
+
overflow: hidden;
|
|
221
186
|
}
|
|
222
187
|
.eg-lsm-footer {
|
|
223
188
|
display: flex;
|
|
@@ -817,10 +817,11 @@
|
|
|
817
817
|
<eg-local-sync-modal
|
|
818
818
|
v-if="localSyncKey"
|
|
819
819
|
:visible="localSyncModal.visible"
|
|
820
|
+
:grid-options="_selfComponentDef"
|
|
820
821
|
:columns="_localSyncPreviewColumns"
|
|
821
822
|
:snapshot="localSyncModal.snapshot"
|
|
822
|
-
:resolve-cell-display="_previewCellDisplay"
|
|
823
823
|
:locale="locale"
|
|
824
|
+
:theme="internalTheme"
|
|
824
825
|
@close="closeLocalSyncModal"
|
|
825
826
|
@save="_onLocalSyncModalSave"
|
|
826
827
|
@restore="restoreLocalSnapshot"
|
|
@@ -980,7 +981,14 @@ const DEFAULT_TOOLBAR_LIST = ['undoRedo', 'export', 'import', 'print', 'localSyn
|
|
|
980
981
|
const COL_DRAG_TRANSITION = 'transform 200ms cubic-bezier(0.2, 0, 0, 1)'
|
|
981
982
|
const THEME_LIST = ['excel', 'material', 'antd', 'fluent', 'carbon']
|
|
982
983
|
|
|
983
|
-
export default {
|
|
984
|
+
// Kept as a named const (rather than an inline `export default {}`) so the
|
|
985
|
+
// local-sync preview modal can receive the plain component definition
|
|
986
|
+
// itself as a prop — see `_selfComponentDef` below. Importing ExcelGrid.vue
|
|
987
|
+
// from EgLocalSyncModal.vue to nest a grid inside it would be a circular
|
|
988
|
+
// import (ExcelGrid.vue -> EgLocalSyncModal.vue -> ExcelGrid.vue); passing
|
|
989
|
+
// this reference down avoids that entirely, and avoids passing `this.$options`
|
|
990
|
+
// (an instance's merged/runtime-contaminated options, not a clean definition).
|
|
991
|
+
const ExcelGridComponent = {
|
|
984
992
|
name: 'ExcelGrid',
|
|
985
993
|
|
|
986
994
|
components: { EgCheckbox, EgSelect, EgTreeSelect, EgDatePicker, EgLocalSyncModal },
|
|
@@ -1679,6 +1687,13 @@ export default {
|
|
|
1679
1687
|
return this.leafCols.filter(col => col.type !== 'action')
|
|
1680
1688
|
},
|
|
1681
1689
|
|
|
1690
|
+
// Passed to EgLocalSyncModal so it can render the snapshot preview as a
|
|
1691
|
+
// real, nested ExcelGrid instance — see the comment on ExcelGridComponent
|
|
1692
|
+
// above for why this is the module-level const and not `this.$options`.
|
|
1693
|
+
_selfComponentDef() {
|
|
1694
|
+
return ExcelGridComponent
|
|
1695
|
+
},
|
|
1696
|
+
|
|
1682
1697
|
_sizeConf() { return SIZE_CONFIG[this.internalSize] || SIZE_CONFIG.middle },
|
|
1683
1698
|
|
|
1684
1699
|
sizeOptions() { return Object.keys(SIZE_CONFIG) },
|
|
@@ -6316,46 +6331,6 @@ export default {
|
|
|
6316
6331
|
this.localSyncModal.visible = false
|
|
6317
6332
|
},
|
|
6318
6333
|
|
|
6319
|
-
// Best-effort display resolver for the modal's read-only preview table.
|
|
6320
|
-
// Deliberately NOT the same as getCellDisplayValue(ci, val, ri): that
|
|
6321
|
-
// method resolves column formatter/select-options against the LIVE grid
|
|
6322
|
-
// (this._dataRaw[ri] at the live row index ri) — meaningless for a
|
|
6323
|
-
// detached IndexedDB snapshot row that may not even correspond to the
|
|
6324
|
-
// same row position in the current data. This takes the row object
|
|
6325
|
-
// directly instead. Function-based (dependent/cascading) col.options
|
|
6326
|
-
// can't be safely resolved without that live per-row context, so those
|
|
6327
|
-
// fall back to showing the raw stored value — a deliberate, explainable
|
|
6328
|
-
// limitation for a preview, not a bug.
|
|
6329
|
-
_previewCellDisplay(row, col) {
|
|
6330
|
-
const val = row ? row[col.key] : null
|
|
6331
|
-
if (!col) return val == null ? '' : val
|
|
6332
|
-
if (typeof col.formatter === 'function') {
|
|
6333
|
-
try {
|
|
6334
|
-
const out = col.formatter(val, row, null, col, col._flatIndex)
|
|
6335
|
-
return out == null ? '' : out
|
|
6336
|
-
} catch (e) {
|
|
6337
|
-
return val == null ? '' : val
|
|
6338
|
-
}
|
|
6339
|
-
}
|
|
6340
|
-
if (col.type === 'checkbox') return val ? '✓' : ''
|
|
6341
|
-
if ((col.type === 'select' || col.type === 'treeSelect') && Array.isArray(col.options)) {
|
|
6342
|
-
const { valueKey, labelKey } = this.treeOptionKeys(col)
|
|
6343
|
-
const v = val == null ? '' : String(val)
|
|
6344
|
-
if (col.type === 'treeSelect') {
|
|
6345
|
-
const found = this._treeFindLabel(col.options, this.treeOptionKeys(col), v)
|
|
6346
|
-
return found != null ? found : v
|
|
6347
|
-
}
|
|
6348
|
-
const found = col.options.find(o => String(typeof o === 'string' ? o : o[valueKey]) === v)
|
|
6349
|
-
if (!found) return v
|
|
6350
|
-
return typeof found === 'string' ? found : (found[labelKey] != null ? found[labelKey] : v)
|
|
6351
|
-
}
|
|
6352
|
-
if (col.type === 'date') {
|
|
6353
|
-
const d = parseDateValue(val)
|
|
6354
|
-
return d ? formatDate(d, col.format || 'YYYY-MM-DD') : (val == null ? '' : val)
|
|
6355
|
-
}
|
|
6356
|
-
return val == null ? '' : val
|
|
6357
|
-
},
|
|
6358
|
-
|
|
6359
6334
|
toggleLock() {
|
|
6360
6335
|
this.internalLocked = !this.internalLocked
|
|
6361
6336
|
this.$emit('update:locked', this.internalLocked)
|
|
@@ -6448,6 +6423,8 @@ export default {
|
|
|
6448
6423
|
}
|
|
6449
6424
|
}
|
|
6450
6425
|
}
|
|
6426
|
+
|
|
6427
|
+
export default ExcelGridComponent
|
|
6451
6428
|
</script>
|
|
6452
6429
|
|
|
6453
6430
|
<style scoped>
|
package/src/utils/i18n.js
CHANGED
|
@@ -51,7 +51,6 @@ const messages = {
|
|
|
51
51
|
localSyncEmpty: 'No local copy saved yet',
|
|
52
52
|
localSyncSavedAt: 'Last saved',
|
|
53
53
|
localSyncRows: 'rows',
|
|
54
|
-
localSyncMoreRows: 'and {n} more row(s)',
|
|
55
54
|
localSyncSave: 'Save',
|
|
56
55
|
localSyncSaveHint: 'Save the current table into the local copy',
|
|
57
56
|
localSyncRestore: 'Restore',
|
|
@@ -123,7 +122,6 @@ const messages = {
|
|
|
123
122
|
localSyncEmpty: 'Локальная копия пока не сохранена',
|
|
124
123
|
localSyncSavedAt: 'Последнее сохранение',
|
|
125
124
|
localSyncRows: 'строк',
|
|
126
|
-
localSyncMoreRows: 'и ещё {n} строк(и)',
|
|
127
125
|
localSyncSave: 'Сохранить',
|
|
128
126
|
localSyncSaveHint: 'Сохранить текущую таблицу в локальную копию',
|
|
129
127
|
localSyncRestore: 'Восстановить',
|
|
@@ -195,7 +193,6 @@ const messages = {
|
|
|
195
193
|
localSyncEmpty: 'Hali lokal saqlangan nusxa yo\'q',
|
|
196
194
|
localSyncSavedAt: 'Oxirgi saqlangan',
|
|
197
195
|
localSyncRows: 'qator',
|
|
198
|
-
localSyncMoreRows: 'va yana {n} ta qator',
|
|
199
196
|
localSyncSave: 'Saqlash',
|
|
200
197
|
localSyncSaveHint: 'Joriy jadvalni lokal nusxaga saqlash',
|
|
201
198
|
localSyncRestore: 'Tiklash',
|
|
@@ -267,7 +264,6 @@ const messages = {
|
|
|
267
264
|
localSyncEmpty: 'Ҳали лакал сақланган нусха йўқ',
|
|
268
265
|
localSyncSavedAt: 'Охирги сақланган',
|
|
269
266
|
localSyncRows: 'қатор',
|
|
270
|
-
localSyncMoreRows: 'ва яна {n} та қатор',
|
|
271
267
|
localSyncSave: 'Сақлаш',
|
|
272
268
|
localSyncSaveHint: 'Жорий жадвални лакал нусхага сақлаш',
|
|
273
269
|
localSyncRestore: 'Тиклаш',
|