flameresttable 1.0.13 → 1.0.15
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 +3 -0
- package/package.json +1 -1
- package/src/App.vue +19 -0
- package/src/Table/Columns.ts +1 -1
- package/src/Table/FlameTable.ts +16 -0
- package/src/Table/Table.vue +44 -20
- package/src/Table/TableFilters.vue +8 -4
- package/src/Table/TableOpts.ts +4 -0
- package/src/Table/TableRowParams.ts +5 -0
package/README.md
CHANGED
package/package.json
CHANGED
package/src/App.vue
CHANGED
|
@@ -20,9 +20,26 @@ onMounted(() => {
|
|
|
20
20
|
|
|
21
21
|
const TableComponent = ref<InstanceType<typeof Table>>();
|
|
22
22
|
const opts = new TableOpts;
|
|
23
|
+
|
|
24
|
+
opts.set('name', { title: 'Название' });
|
|
25
|
+
opts.set('dt1', { title: 'Дата 1' });
|
|
26
|
+
opts.set('dt2', { title: 'Дата 2' });
|
|
27
|
+
opts.set('id', { title: 'Дата 2', Filter: { isShow: false } });
|
|
28
|
+
opts.set('file', { title: 'файл', Filter: { isShow: false } });
|
|
29
|
+
opts.set("name", {
|
|
30
|
+
title: 'Название', Table:
|
|
31
|
+
{
|
|
32
|
+
isRawValue: true,
|
|
33
|
+
isShow: true,
|
|
34
|
+
value: (row, column) => '<a href="https://4h.notion.site/' + row[column.name].replace('-', '') + '">Notion</a>'
|
|
35
|
+
},
|
|
36
|
+
Popup: { isShow: true }
|
|
37
|
+
});
|
|
23
38
|
opts.Add.can = true;
|
|
24
39
|
opts.Remove.can = true;
|
|
25
40
|
|
|
41
|
+
opts.onRowClickOpenSlot = true;
|
|
42
|
+
|
|
26
43
|
// Загружаем первичные данные
|
|
27
44
|
Model.all({ sort: ['id'] }).then(r =>
|
|
28
45
|
TableComponent.value?.Table.load(r)
|
|
@@ -32,6 +49,8 @@ Model.all({ sort: ['id'] }).then(r =>
|
|
|
32
49
|
|
|
33
50
|
<template lang="pug">
|
|
34
51
|
Table(:model="Model", :opts="opts")
|
|
52
|
+
template(v-slot:RowSubSlot="params")
|
|
53
|
+
| {{ params.row.name }}
|
|
35
54
|
</template>
|
|
36
55
|
|
|
37
56
|
<style>
|
package/src/Table/Columns.ts
CHANGED
|
@@ -246,7 +246,7 @@ export interface IColumn {
|
|
|
246
246
|
isShow?: boolean,
|
|
247
247
|
|
|
248
248
|
// Тип фильтра
|
|
249
|
-
type
|
|
249
|
+
type?: "text" | "fixed" | "fulltext" | "number" | "date" | "daterange" | "selector",
|
|
250
250
|
|
|
251
251
|
// Значение
|
|
252
252
|
valueString?: string,
|
package/src/Table/FlameTable.ts
CHANGED
|
@@ -4,6 +4,7 @@ import TableOpts from "./TableOpts";
|
|
|
4
4
|
import { reactive, UnwrapRef } from 'vue';
|
|
5
5
|
import merge from 'lodash-es/merge'
|
|
6
6
|
import ITableLoadParams from './TableLoadParams';
|
|
7
|
+
import TableRowParams from './TableRowParams';
|
|
7
8
|
|
|
8
9
|
// Подгрузчик типа класса
|
|
9
10
|
type Class<T> = new (...args: any[]) => T
|
|
@@ -39,6 +40,11 @@ export default class FlameTable<T> {
|
|
|
39
40
|
*/
|
|
40
41
|
public Rows = reactive({ rows: [] as Array<T> });
|
|
41
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Динамические параметры строк
|
|
45
|
+
*/
|
|
46
|
+
public RowsParams: { [key: string]: TableRowParams } = reactive({});
|
|
47
|
+
|
|
42
48
|
/**
|
|
43
49
|
* Параметры паджинации
|
|
44
50
|
*/
|
|
@@ -110,6 +116,16 @@ export default class FlameTable<T> {
|
|
|
110
116
|
if (rows.data) {
|
|
111
117
|
this.Rows.rows = (rows.data ?? []) as any;
|
|
112
118
|
Object.keys(this.Pager).forEach((key) => (this.Pager as any)[key] = (rows.pages as any)[key])
|
|
119
|
+
|
|
120
|
+
// удаляем чтобы при перезагрузке не сохранялось состояние пред. строк
|
|
121
|
+
// производительность: если не стирать параметры строк, то при долгом пользовании таблицей и больших её объёмах в памяти накопится куча позиций, это утечка
|
|
122
|
+
for (const key in this.RowsParams) delete this.RowsParams[key];
|
|
123
|
+
|
|
124
|
+
// Заполняем параметры каждой строки
|
|
125
|
+
this.Rows.rows.forEach(row => {
|
|
126
|
+
// @ts-expect-error okay
|
|
127
|
+
this.RowsParams[row[this.model.constructor.primaryKeys[0]]] = new TableRowParams
|
|
128
|
+
})
|
|
113
129
|
}
|
|
114
130
|
|
|
115
131
|
}
|
package/src/Table/Table.vue
CHANGED
|
@@ -53,25 +53,30 @@
|
|
|
53
53
|
<!-- СТРОКИ-->
|
|
54
54
|
<div class="table-row-group">
|
|
55
55
|
|
|
56
|
-
<
|
|
57
|
-
class="table-row cursor-pointer hover:bg-slate-100">
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
<template v-for="(row) in (Table.Rows.rows)">
|
|
57
|
+
<div :key="'row_' + (row as any).id" class="table-row cursor-pointer hover:bg-slate-100" v-if="true">
|
|
58
|
+
<div v-for="column in Table.columns" v-show="column.Table.isShow" :key="'tc_' + column"
|
|
59
|
+
class="table-cell border-r border-r-slate-100 px-2 last:border-r-0 last:pr-0"
|
|
60
|
+
@click="columnClick(row, column)">
|
|
61
|
+
<span v-if="!column.Table.isRawValue">{{
|
|
62
|
+
column.Table.value(row, column) }}</span>
|
|
63
|
+
<span v-else v-html="column.Table.value(row, column)"></span>
|
|
64
|
+
</div>
|
|
65
|
+
<div v-if="opts.Edit.can" class="table-cell border-r border-r-slate-100 px-2 text-center">
|
|
66
|
+
<button class="px-2 py-1 bg-green-600 text-white my-1" @click="edit(row)">
|
|
67
|
+
Изменить
|
|
68
|
+
</button>
|
|
69
|
+
</div>
|
|
70
|
+
<div v-if="opts.Remove.can" class="table-cell border-r border-r-slate-100 px-2 text-center">
|
|
71
|
+
<button class="px-2 py-1 bg-gray-600 opacity-30 text-white my-1" @click="deleteRow(row)">
|
|
72
|
+
Удалить
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
68
75
|
</div>
|
|
69
|
-
<div v-if="opts.
|
|
70
|
-
<
|
|
71
|
-
Удалить
|
|
72
|
-
</button>
|
|
76
|
+
<div :key="'row_slot_' + (row as any).id" v-if="opts.onRowClickOpenSlot && !isRowCollapsed(row)">
|
|
77
|
+
<slot name="RowSubSlot" :row="row" />
|
|
73
78
|
</div>
|
|
74
|
-
</
|
|
79
|
+
</template>
|
|
75
80
|
</div>
|
|
76
81
|
|
|
77
82
|
</div>
|
|
@@ -194,7 +199,7 @@ import { onMounted, reactive, ref, defineProps } from '@vue/runtime-core'; impor
|
|
|
194
199
|
// Иконки
|
|
195
200
|
import { XCircleIcon } from '@icons/24/solid'
|
|
196
201
|
import { computed } from '@vue/reactivity';
|
|
197
|
-
import { Column } from './Columns';
|
|
202
|
+
import { Column, IColumn } from './Columns';
|
|
198
203
|
import { defineComponent } from 'vue';
|
|
199
204
|
import TableOpts from './TableOpts';
|
|
200
205
|
import FlameTable from './FlameTable';
|
|
@@ -322,6 +327,22 @@ export default defineComponent({
|
|
|
322
327
|
})
|
|
323
328
|
}
|
|
324
329
|
|
|
330
|
+
const primaryKey = (Table.model as any).constructor.primaryKeys[0];
|
|
331
|
+
|
|
332
|
+
const columnClick = (row: any, column: Column) => {
|
|
333
|
+
if (Table.opts.onRowClickOpenSlot) {
|
|
334
|
+
Table.RowsParams[row[primaryKey]].collapsed = !Table.RowsParams[row[primaryKey]].collapsed
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
if (column?.Table?.click !== undefined)
|
|
338
|
+
column.Table.click(row, column);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const isRowCollapsed = (row: any) => {
|
|
342
|
+
return Table.RowsParams[row[primaryKey]].collapsed
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
|
|
325
346
|
return {
|
|
326
347
|
Table,
|
|
327
348
|
FlameTableModal,
|
|
@@ -331,7 +352,10 @@ export default defineComponent({
|
|
|
331
352
|
SaveTable,
|
|
332
353
|
deleteRow,
|
|
333
354
|
fileUpdated,
|
|
334
|
-
getSelector
|
|
355
|
+
getSelector,
|
|
356
|
+
primaryKey,
|
|
357
|
+
columnClick,
|
|
358
|
+
isRowCollapsed
|
|
335
359
|
}
|
|
336
360
|
|
|
337
361
|
},
|
|
@@ -368,7 +392,7 @@ export default defineComponent({
|
|
|
368
392
|
}
|
|
369
393
|
}
|
|
370
394
|
}
|
|
371
|
-
}
|
|
395
|
+
},
|
|
372
396
|
},
|
|
373
397
|
|
|
374
398
|
})
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="fc flex-wrap">
|
|
3
|
-
<div v-for="(col) in props.columns" :key="col.name">
|
|
4
|
-
|
|
3
|
+
<div v-for="(col) in props.columns" :key="col.name" v-show="col.Filter.isShow">
|
|
4
|
+
|
|
5
5
|
<!-- ТЕКСТ -->
|
|
6
|
-
<div
|
|
7
|
-
<
|
|
6
|
+
<div class="fc flex-col">
|
|
7
|
+
<div class="text-xs text-slate-400">{{ col.title.toUpperCase() ?? col.name }}</div>
|
|
8
|
+
<div v-if="col.Filter.type === 'text' || col.Filter.type === 'fixed' || col.Filter.type === 'fulltext'">
|
|
9
|
+
<input class="outline-none border border-slate-500 px-2 py-1 mx-2" :placeholder="col.title ?? col.name"
|
|
10
|
+
type="text" @keyup="update()" v-model="col.Filter.valueString" />
|
|
11
|
+
</div>
|
|
8
12
|
</div>
|
|
9
13
|
|
|
10
14
|
</div>
|
package/src/Table/TableOpts.ts
CHANGED
|
@@ -21,6 +21,10 @@ export default class TableOpts {
|
|
|
21
21
|
*/
|
|
22
22
|
public LoadParams: ITableLoadParams = {};
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Открывать субслот в таблице при клике
|
|
26
|
+
*/
|
|
27
|
+
public onRowClickOpenSlot: boolean = false;
|
|
24
28
|
|
|
25
29
|
public set(ColumnName: string, mergingOpts: IColumn) {
|
|
26
30
|
// TODO: ЕСТЬ ОШИБКА???
|