flameresttable 1.0.118 → 1.0.122
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/package.json +17 -17
- package/src/App.vue +16 -17
- package/src/Table/Columns.ts +75 -14
- package/src/Table/FlameTable.ts +95 -12
- package/src/Table/Paginator.vue +37 -19
- package/src/Table/Table.vue +23 -247
- package/src/Table/TableFilters.vue +89 -19
- package/src/Table/TableOpts.ts +5 -0
- package/src/Table/TablePopup.vue +324 -0
- package/src/Table/TableSelectorItem.ts +22 -2
- package/src/Table/TableTasksPanel.vue +1 -1
- package/src/components/default/Modal.vue +37 -32
- package/src/components/editor/EditorPopup.vue +1 -1
- package/src/components/editor/LinkDialog.vue +1 -1
- package/src/components/editor/SelectImage.vue +1 -1
- package/src/main.ts +4 -6
- package/src/pages/Home.vue +5 -6
- package/src/pages/SubRow.vue +28 -24
package/package.json
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flameresttable",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.122",
|
|
4
4
|
"main": "./src/plugin.ts",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/FlameArt/resttable.git"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"
|
|
10
|
+
"publish": "npm --no-git-tag-version version patch && npm publish",
|
|
11
11
|
"install/update": "npm i && npm update --save",
|
|
12
12
|
"dev": "vite"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@vuepic/vue-datepicker": "^11.0.
|
|
16
|
-
"flamerest": "
|
|
17
|
-
"lodash-es": "^4.17.
|
|
15
|
+
"@vuepic/vue-datepicker": "^11.0.3",
|
|
16
|
+
"flamerest": "file:../REST JS",
|
|
17
|
+
"lodash-es": "^4.17.23",
|
|
18
18
|
"pinia": "^2.3.1",
|
|
19
19
|
"pug": "github:FlameArt/pug-tailwind-only",
|
|
20
20
|
"pug-lexer": "github:FlameArt/pug-lexer-only",
|
|
21
|
-
"sass": "^1.
|
|
21
|
+
"sass": "^1.97.3",
|
|
22
22
|
"vue": "^3.5.13",
|
|
23
|
-
"vue-router": "^4.
|
|
23
|
+
"vue-router": "^4.6.4",
|
|
24
24
|
"vue-select": "^4.0.0-beta.6",
|
|
25
|
-
"vuetify": "^3.8
|
|
26
|
-
"vuetify-pro-tiptap": "^2.
|
|
25
|
+
"vuetify": "^3.11.8",
|
|
26
|
+
"vuetify-pro-tiptap": "^2.8.2"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@heroicons/vue": "^2.2.0",
|
|
30
30
|
"@types/lodash-es": "^4.17.12",
|
|
31
31
|
"@types/lodash.merge": "^4.6.9",
|
|
32
|
-
"@types/node": "^22.
|
|
32
|
+
"@types/node": "^22.19.7",
|
|
33
33
|
"@types/vue-select": "^3.16.8",
|
|
34
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
35
|
-
"@typescript-eslint/parser": "^8.
|
|
34
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
35
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
36
36
|
"@vitejs/plugin-vue": "^5.2.4",
|
|
37
37
|
"@volar/vue-language-plugin-pug": "^1.6.5",
|
|
38
38
|
"@vue/compiler-sfc": "^3.5.13",
|
|
39
|
-
"autoprefixer": "^10.4.
|
|
40
|
-
"eslint": "^9.
|
|
39
|
+
"autoprefixer": "^10.4.24",
|
|
40
|
+
"eslint": "^9.39.2",
|
|
41
41
|
"eslint-plugin-vue": "^9.33.0",
|
|
42
42
|
"postcss": "^8.5.6",
|
|
43
43
|
"postcss-import": "^16.1.1",
|
|
44
|
-
"tailwindcss": "^3.4.
|
|
45
|
-
"typescript": "^5.
|
|
46
|
-
"vite": "^6.
|
|
44
|
+
"tailwindcss": "^3.4.19",
|
|
45
|
+
"typescript": "^5.9.3",
|
|
46
|
+
"vite": "^6.4.1",
|
|
47
47
|
"vue-tsc": "^2.2.12",
|
|
48
48
|
"vue-universal-modal": "^1.1.4"
|
|
49
49
|
},
|
package/src/App.vue
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-app>
|
|
3
|
+
<v-main>
|
|
4
|
+
<Table :model="Model" :opts="opts">
|
|
5
|
+
<template v-slot:RowSubSlot="params">
|
|
6
|
+
<!-- {{ params.row.name + ' LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG line' }} -->
|
|
7
|
+
<!-- <SubRow /> -->
|
|
8
|
+
<div class="flex items-center justify-center w-full mx-auto">AAA</div>
|
|
9
|
+
</template>
|
|
10
|
+
<template #otherButtons></template>
|
|
11
|
+
</Table>
|
|
12
|
+
</v-main>
|
|
13
|
+
</v-app>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
1
16
|
<script setup lang="ts">
|
|
2
|
-
import { onMounted, reactive
|
|
17
|
+
import { onMounted, reactive } from 'vue'; import { storeFile } from "@/store"; import { useRoute, useRouter } from 'vue-router'; import REST from "flamerest"
|
|
3
18
|
import Table from './Table/Table.vue';
|
|
4
19
|
import { ref } from 'vue';
|
|
5
20
|
import Model from '@models/Testtable';
|
|
@@ -55,26 +70,10 @@ opts.LoadParams.sort = ['-dt1'];
|
|
|
55
70
|
|
|
56
71
|
</script>
|
|
57
72
|
|
|
58
|
-
<template lang="pug">
|
|
59
|
-
v-app
|
|
60
|
-
v-main
|
|
61
|
-
Table(:model="Model", :opts="opts")
|
|
62
|
-
template(v-slot:RowSubSlot="params")
|
|
63
|
-
//| {{ params.row.name + ' LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG line' }}
|
|
64
|
-
//SubRow
|
|
65
|
-
div(class="flex items-center justify-center w-full mx-auto") AAA
|
|
66
|
-
template(#otherButtons)
|
|
67
|
-
</template>
|
|
68
|
-
|
|
69
73
|
<style>
|
|
70
74
|
#app {
|
|
71
75
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
|
72
76
|
-webkit-font-smoothing: antialiased;
|
|
73
77
|
-moz-osx-font-smoothing: grayscale;
|
|
74
78
|
}
|
|
75
|
-
|
|
76
|
-
/* Цвет стандартного фона модального окна */
|
|
77
|
-
.vue-universal-modal {
|
|
78
|
-
background-color: rgba(0, 0, 0, 0.15) !important;
|
|
79
|
-
}
|
|
80
79
|
</style>
|
package/src/Table/Columns.ts
CHANGED
|
@@ -30,6 +30,11 @@ export class Column implements IColumn {
|
|
|
30
30
|
*/
|
|
31
31
|
isShow: true,
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Позиция колонки для сортировки
|
|
35
|
+
*/
|
|
36
|
+
position: 999,
|
|
37
|
+
|
|
33
38
|
/**
|
|
34
39
|
* Заголовок столбца в таблице
|
|
35
40
|
*/
|
|
@@ -118,13 +123,23 @@ export class Column implements IColumn {
|
|
|
118
123
|
*/
|
|
119
124
|
values: [] as ITableSelectorItem[],
|
|
120
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Разрешить выбирать пустое значение (null)
|
|
128
|
+
*/
|
|
129
|
+
allowNull: true,
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Заголовок для пустого значения
|
|
133
|
+
*/
|
|
134
|
+
nullTitle: "—",
|
|
135
|
+
|
|
121
136
|
/**
|
|
122
137
|
* Кастомизация вывода отдельного элемента
|
|
123
138
|
* @param row
|
|
124
139
|
* @param col
|
|
125
140
|
* @returns
|
|
126
141
|
*/
|
|
127
|
-
value: (row: any, col: string) => row[col]
|
|
142
|
+
value: (row: any, col: string) => row[col],
|
|
128
143
|
|
|
129
144
|
};
|
|
130
145
|
|
|
@@ -158,9 +173,15 @@ export class Column implements IColumn {
|
|
|
158
173
|
// Минимальное число символов в строке фильтра, после которого будет произведён запрос
|
|
159
174
|
filterMinSymbolsRequest: 0,
|
|
160
175
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
176
|
+
/**
|
|
177
|
+
* Позиция фильтра в общей очереди
|
|
178
|
+
*/
|
|
179
|
+
position: 999,
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Ширина фильтра в пикселях
|
|
183
|
+
*/
|
|
184
|
+
width: null as number | null,
|
|
164
185
|
|
|
165
186
|
/**
|
|
166
187
|
* CSS-классы,
|
|
@@ -182,7 +203,7 @@ export class Column implements IColumn {
|
|
|
182
203
|
public Popup = {
|
|
183
204
|
|
|
184
205
|
// Тут привязка к реальным данным
|
|
185
|
-
model: "",
|
|
206
|
+
model: "" as any,
|
|
186
207
|
|
|
187
208
|
// Тут модель для файлов
|
|
188
209
|
fileModel: null as any,
|
|
@@ -225,10 +246,20 @@ export class Column implements IColumn {
|
|
|
225
246
|
Selector: {
|
|
226
247
|
|
|
227
248
|
// Значения селектора - готовые
|
|
228
|
-
values: [],
|
|
249
|
+
values: [] as ITableSelectorItem[],
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Разрешить выбирать пустое значение (null)
|
|
253
|
+
*/
|
|
254
|
+
allowNull: false,
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Заголовок для пустого значения
|
|
258
|
+
*/
|
|
259
|
+
nullTitle: "—",
|
|
229
260
|
|
|
230
261
|
// Загрузчик значений - используется всегда и перекрывает values
|
|
231
|
-
loader: (column: Column) => null
|
|
262
|
+
loader: (column: Column) => null as ITableSelectorItem[] | null,
|
|
232
263
|
|
|
233
264
|
},
|
|
234
265
|
|
|
@@ -318,6 +349,11 @@ export interface IColumn {
|
|
|
318
349
|
width?: number | null,
|
|
319
350
|
isSelected?: boolean,
|
|
320
351
|
|
|
352
|
+
/**
|
|
353
|
+
* Позиция колонки для сортировки
|
|
354
|
+
*/
|
|
355
|
+
position?: number,
|
|
356
|
+
|
|
321
357
|
/**
|
|
322
358
|
* Кастомный заголовок
|
|
323
359
|
* @param row
|
|
@@ -350,9 +386,15 @@ export interface IColumn {
|
|
|
350
386
|
// Минимальное число символов в строке фильтра, после которого будет произведён запрос
|
|
351
387
|
filterMinSymbolsRequest?: number,
|
|
352
388
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
389
|
+
/**
|
|
390
|
+
* Позиция фильтра в общей очереди
|
|
391
|
+
*/
|
|
392
|
+
position?: number,
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Ширина фильтра в пикселях
|
|
396
|
+
*/
|
|
397
|
+
width?: number | null,
|
|
356
398
|
|
|
357
399
|
/**
|
|
358
400
|
* Список значений под выбор
|
|
@@ -405,6 +447,16 @@ export interface IColumn {
|
|
|
405
447
|
*/
|
|
406
448
|
values?: ITableSelectorItem[],
|
|
407
449
|
|
|
450
|
+
/**
|
|
451
|
+
* Разрешить выбирать пустое значение (null)
|
|
452
|
+
*/
|
|
453
|
+
allowNull?: boolean,
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Заголовок для пустого значения
|
|
457
|
+
*/
|
|
458
|
+
nullTitle?: string,
|
|
459
|
+
|
|
408
460
|
|
|
409
461
|
/**
|
|
410
462
|
* Модель, с которой выгружать значения
|
|
@@ -418,7 +470,7 @@ export interface IColumn {
|
|
|
418
470
|
* @param col
|
|
419
471
|
* @returns
|
|
420
472
|
*/
|
|
421
|
-
value?: (row: any, col: string) => any
|
|
473
|
+
value?: (row: any, col: string) => any,
|
|
422
474
|
|
|
423
475
|
},
|
|
424
476
|
|
|
@@ -466,15 +518,24 @@ export interface IColumn {
|
|
|
466
518
|
// Текст ошибки добавления/обновления
|
|
467
519
|
errorMessage?: string,
|
|
468
520
|
|
|
469
|
-
|
|
470
521
|
// Настройки селектора, если он включён в popupType
|
|
471
522
|
Selector?: {
|
|
472
523
|
|
|
473
524
|
// Значения селектора - готовые
|
|
474
|
-
values?:
|
|
525
|
+
values?: ITableSelectorItem[],
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Разрешить выбирать пустое значение (null)
|
|
529
|
+
*/
|
|
530
|
+
allowNull?: boolean,
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Заголовок для пустого значения
|
|
534
|
+
*/
|
|
535
|
+
nullTitle?: string,
|
|
475
536
|
|
|
476
537
|
// Загрузчик значений - используется всегда и перекрывает values
|
|
477
|
-
loader?: (column: Column) =>
|
|
538
|
+
loader?: (column: Column) => ITableSelectorItem[] | null,
|
|
478
539
|
|
|
479
540
|
},
|
|
480
541
|
|
package/src/Table/FlameTable.ts
CHANGED
|
@@ -94,11 +94,12 @@ export default class FlameTable<T> {
|
|
|
94
94
|
// удалим так же дубликаты
|
|
95
95
|
// TODO: as any
|
|
96
96
|
const allColumns = [...Object.keys(this.model as any), ...Object.keys(opts.columnsOpts)].filter((value, index, self) => self.indexOf(value) === index)
|
|
97
|
+
const tempColumns: Column[] = [];
|
|
97
98
|
|
|
98
99
|
// генерим полноценные колонки из описания модели
|
|
99
100
|
for (const key of allColumns) {
|
|
100
101
|
const newCol = new Column;
|
|
101
|
-
this.columns[key] = newCol;
|
|
102
|
+
//this.columns[key] = newCol;
|
|
102
103
|
|
|
103
104
|
// Выключаем из редактирования все праймари ключи
|
|
104
105
|
if ((this.model as any).constructor['primaryKeys'].includes(key))
|
|
@@ -111,14 +112,28 @@ export default class FlameTable<T> {
|
|
|
111
112
|
newCol.name = key;
|
|
112
113
|
|
|
113
114
|
// Загружаем селекторы один раз за страницу
|
|
114
|
-
if (newCol.Popup.popupType === 'selector' && newCol.Popup.Selector.loader !== null)
|
|
115
|
+
if (newCol.Popup.popupType === 'selector' && newCol.Popup.Selector.loader !== null) {
|
|
115
116
|
newCol.Popup.Selector.values = reactive(newCol.Popup.Selector.loader(newCol) ?? newCol.Popup.Selector.values)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
tempColumns.push(newCol);
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Сортируем колонки по их позиции
|
|
124
|
+
tempColumns.sort((a, b) => (a.Table.position ?? 999) - (b.Table.position ?? 999));
|
|
116
125
|
|
|
126
|
+
// Заполняем итоговый объект в правильном порядке
|
|
127
|
+
for (const col of tempColumns) {
|
|
128
|
+
this.columns[col.name] = col;
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
// Мержим параметры с базовой версией
|
|
120
132
|
merge(this.opts, opts);
|
|
121
133
|
|
|
134
|
+
// Устанавливаем ссылку на таблицу для обратного вызова
|
|
135
|
+
(this.opts as any)._tableInstance = this;
|
|
136
|
+
|
|
122
137
|
// TODO: Сортируем колонки, если указан порядок
|
|
123
138
|
//this.columns
|
|
124
139
|
|
|
@@ -127,7 +142,8 @@ export default class FlameTable<T> {
|
|
|
127
142
|
// Предзагружаем колонки
|
|
128
143
|
this.preloadRelated()
|
|
129
144
|
|
|
130
|
-
|
|
145
|
+
// Инициализируем null-элементы для селекторов
|
|
146
|
+
this.initSelectorNulls()
|
|
131
147
|
|
|
132
148
|
}
|
|
133
149
|
|
|
@@ -196,6 +212,7 @@ export default class FlameTable<T> {
|
|
|
196
212
|
col.Selector.values.push(...col.Selector.loader(r.data))
|
|
197
213
|
}
|
|
198
214
|
|
|
215
|
+
|
|
199
216
|
// Преобразования не найдено, попытка автоматически определить параметры
|
|
200
217
|
if (col.Selector.loader === null) {
|
|
201
218
|
const rows = r.data;
|
|
@@ -227,6 +244,59 @@ export default class FlameTable<T> {
|
|
|
227
244
|
|
|
228
245
|
}
|
|
229
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Переинициализирует селекторы для указанной колонки
|
|
249
|
+
*/
|
|
250
|
+
public reinitSelectorForColumn(columnName: string) {
|
|
251
|
+
if (!this.columns[columnName]) return
|
|
252
|
+
|
|
253
|
+
const col = this.columns[columnName]
|
|
254
|
+
|
|
255
|
+
// Для popup selector
|
|
256
|
+
if (col.Popup.popupType === 'selector') {
|
|
257
|
+
// Удаляем существующий null-элемент если есть
|
|
258
|
+
col.Popup.Selector.values = col.Popup.Selector.values.filter(v => v.id !== null)
|
|
259
|
+
|
|
260
|
+
// Добавляем null только если allowNull = true
|
|
261
|
+
if (col.Popup.Selector.allowNull) {
|
|
262
|
+
col.Popup.Selector.values.unshift({
|
|
263
|
+
id: null,
|
|
264
|
+
title: col.Popup.Selector.nullTitle,
|
|
265
|
+
label: col.Popup.Selector.nullTitle,
|
|
266
|
+
})
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Для обычного селектора (фильтры)
|
|
271
|
+
if (col.Selector.allowNull) {
|
|
272
|
+
// Удаляем существующий null-элемент если есть
|
|
273
|
+
col.Selector.values = col.Selector.values.filter(v => v.id !== null)
|
|
274
|
+
|
|
275
|
+
col.Selector.values.unshift({
|
|
276
|
+
id: null,
|
|
277
|
+
title: col.Selector.nullTitle,
|
|
278
|
+
label: col.Selector.nullTitle,
|
|
279
|
+
position: -1
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Инициализирует null-элементы для всех селекторов, где allowNull = true
|
|
286
|
+
*/
|
|
287
|
+
private initSelectorNulls() {
|
|
288
|
+
for (const key in this.columns) {
|
|
289
|
+
this.reinitSelectorForColumn(key)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Переинициализирует все селекторы (можно вызывать после изменения данных в лоадерах)
|
|
295
|
+
*/
|
|
296
|
+
public reinitSelectors() {
|
|
297
|
+
this.initSelectorNulls()
|
|
298
|
+
}
|
|
299
|
+
|
|
230
300
|
/**
|
|
231
301
|
* Обновить результаты от RESTа
|
|
232
302
|
* @param CustomLoadParams Применить кастомные параметры загрузки
|
|
@@ -234,6 +304,17 @@ export default class FlameTable<T> {
|
|
|
234
304
|
*/
|
|
235
305
|
public async update(CustomLoadParams: ITableLoadParams = {}, exportFilename: string | null = null, from: 'pager' | 'filters' = 'pager') {
|
|
236
306
|
|
|
307
|
+
if (from !== 'pager') {
|
|
308
|
+
this.Pager.page = 1;
|
|
309
|
+
|
|
310
|
+
// Сбрасываем выделенные строки
|
|
311
|
+
for (const key in this.RowsParams) {
|
|
312
|
+
this.RowsParams[key].selected = false;
|
|
313
|
+
}
|
|
314
|
+
this.RowsSelected.splice(0);
|
|
315
|
+
|
|
316
|
+
}
|
|
317
|
+
|
|
237
318
|
// Дополняем загрузочные параметры фильтрами
|
|
238
319
|
const filters = merge(this.applyFiltersParams(), CustomLoadParams);
|
|
239
320
|
|
|
@@ -335,7 +416,7 @@ export default class FlameTable<T> {
|
|
|
335
416
|
// Частичное совпадение
|
|
336
417
|
case 'text':
|
|
337
418
|
|
|
338
|
-
if (el.valueString.trim() === '') continue;
|
|
419
|
+
if (el.valueString === null || el.valueString.trim() === '') continue;
|
|
339
420
|
customFilters.where[key] = ['LIKE', key, el.valueString];
|
|
340
421
|
|
|
341
422
|
break;
|
|
@@ -343,7 +424,7 @@ export default class FlameTable<T> {
|
|
|
343
424
|
// Фуллтекстовый поиск
|
|
344
425
|
case 'fulltext':
|
|
345
426
|
|
|
346
|
-
if (el.valueString.trim() === '') continue;
|
|
427
|
+
if (el.valueString === null || el.valueString.trim() === '') continue;
|
|
347
428
|
customFilters.where[key] = ['FULLTEXT', key, el.valueString];
|
|
348
429
|
break;
|
|
349
430
|
|
|
@@ -351,7 +432,7 @@ export default class FlameTable<T> {
|
|
|
351
432
|
case 'fixed':
|
|
352
433
|
case 'date':
|
|
353
434
|
|
|
354
|
-
if (el.valueString.trim() === '') continue;
|
|
435
|
+
if (el.valueString === null || el.valueString.trim() === '') continue;
|
|
355
436
|
customFilters.where[key] = el.valueString;
|
|
356
437
|
|
|
357
438
|
break;
|
|
@@ -384,8 +465,10 @@ export default class FlameTable<T> {
|
|
|
384
465
|
if (el.valueRange.length > 0)
|
|
385
466
|
customFilters.where[key] = ['IN', key, el.valueRange];
|
|
386
467
|
}
|
|
387
|
-
else
|
|
388
|
-
|
|
468
|
+
else {
|
|
469
|
+
if (el.valueString !== "")
|
|
470
|
+
customFilters.where[key] = el.valueString;
|
|
471
|
+
}
|
|
389
472
|
|
|
390
473
|
break;
|
|
391
474
|
|
|
@@ -401,7 +484,7 @@ export default class FlameTable<T> {
|
|
|
401
484
|
|
|
402
485
|
// Сперва предобработка
|
|
403
486
|
// TODO: убрать пустой массив т.к. при добавлении он не нужен или прикрепить реактивную модель?
|
|
404
|
-
if (await this.opts.Popup.beforeAdd({}, this) === false) { return null; }
|
|
487
|
+
if (await this.opts.Popup.beforeAdd({}, this as any) === false) { return null; }
|
|
405
488
|
|
|
406
489
|
const cols = await (window as any).REST.prepare(this.getColumnsForUpdate('add'), true);
|
|
407
490
|
const res: SavedObject<T> = await Object.getPrototypeOf(this.model).constructor.create(cols);
|
|
@@ -423,7 +506,7 @@ export default class FlameTable<T> {
|
|
|
423
506
|
const indexKey = tClass.primaryKeys[0];
|
|
424
507
|
|
|
425
508
|
// Сперва предобработка
|
|
426
|
-
if (await this.opts.Popup.beforeEdit(columns, this) === false) { return null; }
|
|
509
|
+
if (await this.opts.Popup.beforeEdit(columns, this as any) === false) { return null; }
|
|
427
510
|
|
|
428
511
|
// Убираем поля, которые не требуют изменения
|
|
429
512
|
const cleanedCols = this.RemoveUnchagedFields(columns);
|
|
@@ -456,7 +539,7 @@ export default class FlameTable<T> {
|
|
|
456
539
|
|
|
457
540
|
}
|
|
458
541
|
|
|
459
|
-
|
|
542
|
+
public RemoveUnchagedFields(row: { [key: string]: any }) {
|
|
460
543
|
|
|
461
544
|
// primarykey
|
|
462
545
|
const pk = (this.model as any).constructor.primaryKeys[0];
|
|
@@ -507,7 +590,7 @@ export default class FlameTable<T> {
|
|
|
507
590
|
|
|
508
591
|
}
|
|
509
592
|
|
|
510
|
-
|
|
593
|
+
public getColumnsForUpdate(mode: "add" | "edit") {
|
|
511
594
|
const res: { [key: string]: string } = {};
|
|
512
595
|
for (const key in this.columns) {
|
|
513
596
|
|
package/src/Table/Paginator.vue
CHANGED
|
@@ -1,25 +1,43 @@
|
|
|
1
|
-
<template
|
|
2
|
-
nav
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<nav class="relative z-0 w-full fc flex-wrap rounded-md -space-x-px" aria-label="Pagination" @click="">
|
|
3
|
+
<a
|
|
4
|
+
class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
|
|
5
|
+
@click="goPage(props.table.Pager.page - 1)"
|
|
6
|
+
:class="props.table.Pager.page === 1 ? 'opacity-30' : 'cursor-pointer'"
|
|
7
|
+
>
|
|
8
|
+
<span class="sr-only">Previous</span>
|
|
9
|
+
<!-- Heroicon name: solid/chevron-left -->
|
|
10
|
+
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
11
|
+
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"></path>
|
|
12
|
+
</svg>
|
|
13
|
+
</a>
|
|
14
|
+
<!-- Current: "z-10 bg-indigo-50 border-indigo-500 text-indigo-600", Default: "bg-white border-gray-300 text-gray-500 hover:bg-gray-50" -->
|
|
15
|
+
<a
|
|
16
|
+
class="cursor-pointer bg-white border-gray-300 text-gray-500 relative inline-flex items-center px-4 py-2 border text-sm font-medium hover:bg-gray-50"
|
|
17
|
+
v-for="page in props.table.Pager.count"
|
|
18
|
+
:key="page"
|
|
19
|
+
:class="props.table.Pager.page === page ? 'selectedPage' : ''"
|
|
20
|
+
@click="goPage(page)"
|
|
21
|
+
>
|
|
22
|
+
{{ page }}
|
|
23
|
+
</a>
|
|
24
|
+
<!-- <span class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700">...</span> -->
|
|
25
|
+
<a
|
|
26
|
+
class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
|
|
27
|
+
@click="goPage(props.table.Pager.page + 1)"
|
|
28
|
+
:class="props.table.Pager.page >= props.table.Pager.count ? 'opacity-30' : 'cursor-pointer'"
|
|
29
|
+
>
|
|
30
|
+
<span class="sr-only">Next</span>
|
|
31
|
+
<!-- Heroicon name: solid/chevron-right -->
|
|
32
|
+
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
33
|
+
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
|
34
|
+
</svg>
|
|
35
|
+
</a>
|
|
36
|
+
</nav>
|
|
19
37
|
</template>
|
|
20
38
|
|
|
21
39
|
<script setup lang="ts">
|
|
22
|
-
import { onMounted, reactive, ref
|
|
40
|
+
import { onMounted, reactive, ref } from 'vue'; import type { Ref } from 'vue'; import { storeFile } from "@/store"; import { useRoute, useRouter } from 'vue-router'; import REST from "flamerest"
|
|
23
41
|
|
|
24
42
|
// Иконки
|
|
25
43
|
import { XCircleIcon } from '@icons/24/solid'
|