flameresttable 1.0.21 → 1.0.23

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/.eslintrc CHANGED
@@ -16,7 +16,14 @@
16
16
  "vue/no-multiple-template-root": "off",
17
17
  "vue/no-duplicate-attributes": "off",
18
18
  "linebreak-style": "off",
19
- "vue/multiline-html-element-content-newline": "off"
19
+ "vue/multiline-html-element-content-newline": "off",
20
+ "vue/attributes-order": "off",
21
+ "vue/html-closing-bracket-newline": "off",
22
+ "vue/html-self-closing": "off",
23
+ "vue/max-attributes-per-line": "off",
24
+ "vue/first-attribute-linebreak": "off",
25
+ "vue/html-indent": "off",
26
+ "vue/no-v-html": "off"
20
27
  },
21
28
  "plugins": [
22
29
  "@typescript-eslint"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flameresttable",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "main": "./src/plugin.ts",
5
5
  "repository": {
6
6
  "type": "git",
package/src/App.vue CHANGED
@@ -38,6 +38,7 @@ opts.set("name", {
38
38
 
39
39
 
40
40
  opts.addVirtual('test', { title: 'test title', Table: { isShow: true, } })
41
+ opts.addVirtual('date', { title: 'dt', Filter: { isShow: true, type: 'daterange' }, Table: { isShow: true, } })
41
42
 
42
43
  opts.Add.can = true;
43
44
  opts.Remove.can = true;
@@ -51,7 +52,7 @@ opts.LoadParams.sort = ['-dt1'];
51
52
  <template lang="pug">
52
53
  Table(:model="Model", :opts="opts")
53
54
  template(v-slot:RowSubSlot="params")
54
- | {{ params.row.name }}
55
+ | {{ params.row.name + ' LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG LOOOONG line' }}
55
56
  </template>
56
57
 
57
58
  <style>
@@ -33,6 +33,11 @@ export class Column implements IColumn {
33
33
  */
34
34
  title: "",
35
35
 
36
+ /**
37
+ * Выделена ли строка чекбоксом
38
+ */
39
+ isSelected: false,
40
+
36
41
  /**
37
42
  * Возможность преобразовать вывод из любой колонки
38
43
  * @param row строка
@@ -57,7 +62,22 @@ export class Column implements IColumn {
57
62
  * @param column
58
63
  * @returns
59
64
  */
60
- click: (row: any, column: Column) => { }
65
+ click: (row: any, column: Column) => { },
66
+
67
+ /**
68
+ * CSS-классы колонки в таблице
69
+ */
70
+ classes: '',
71
+
72
+ /**
73
+ * CSS-классы заголовка таблице
74
+ */
75
+ classesHeader: '',
76
+
77
+ /**
78
+ * Ширина таблицы
79
+ */
80
+ width: null,
61
81
 
62
82
  }
63
83
 
@@ -102,7 +122,7 @@ export class Column implements IColumn {
102
122
 
103
123
  // Значение
104
124
  valueString: "",
105
- valueRange: { from: '', to: '' },
125
+ valueRange: [],
106
126
 
107
127
  // Тип фильтра
108
128
  type: 'text' as "text" | "fixed" | "fulltext" | "number" | "date" | "daterange" | "selector",
@@ -117,7 +137,12 @@ export class Column implements IColumn {
117
137
 
118
138
  // Позиция фильтра по порядку
119
139
  filterRow: 0,
120
- filterColumn: 0
140
+ filterColumn: 0,
141
+
142
+ /**
143
+ * CSS-классы,
144
+ */
145
+ classes: '',
121
146
 
122
147
  }
123
148
 
@@ -251,7 +276,11 @@ export interface IColumn {
251
276
  title?: string,
252
277
  value?: (row: any, column: Column) => string,
253
278
  isRawValue?: boolean,
254
- click?: (row: any, column: Column) => void
279
+ click?: (row: any, column: Column) => void,
280
+ classes?: string,
281
+ classesHeader?: string,
282
+ width?: number | null,
283
+ isSelected?: boolean,
255
284
  },
256
285
 
257
286
  /**
@@ -267,7 +296,7 @@ export interface IColumn {
267
296
 
268
297
  // Значение
269
298
  valueString?: string,
270
- valueRange?: { from: string, to: string },
299
+ valueRange?: Array<string>,
271
300
 
272
301
  // Минимальное число символов в строке фильтра, после которого будет произведён запрос
273
302
  filterMinSymbolsRequest?: number,
@@ -60,6 +60,11 @@ export default class FlameTable<T> {
60
60
  */
61
61
  public OpenedRow: any = null;
62
62
 
63
+ /**
64
+ * Выделенные галочками чекбоксы
65
+ */
66
+ public RowsSelected: Array<T> = [];
67
+
63
68
  /**
64
69
  * Проинициализировать модели
65
70
  */
@@ -192,10 +197,10 @@ export default class FlameTable<T> {
192
197
  case 'number':
193
198
  case 'daterange':
194
199
 
195
- if (el.valueRange.from.trim() !== '')
196
- customFilters.where[key] = ['>=', key, el.valueRange.from];
197
- if (el.valueRange.to.trim() !== '')
198
- customFilters.where[key] = ['<=', key, el.valueRange.to];
200
+ if (el.valueRange.length > 0) {
201
+ customFilters.where[key] = ['>=', key, el.valueRange[0]];
202
+ customFilters.where[key] = ['<=', key, el.valueRange[1]];
203
+ }
199
204
 
200
205
  break;
201
206
 
@@ -278,6 +283,14 @@ export default class FlameTable<T> {
278
283
  return res;
279
284
  }
280
285
 
281
-
286
+ public getSelectedRows() {
287
+ const result: Array<T> = [];
288
+ this.Rows.rows.forEach((r: any) => {
289
+ const param = this.RowsParams[r[(this.model as any).constructor.primaryKeys[0]]]
290
+ if (param.selected)
291
+ result.push(r)
292
+ })
293
+ return result;
294
+ }
282
295
 
283
296
  }
@@ -8,7 +8,7 @@
8
8
  <div class="flex items-center justify-between">
9
9
  <slot name="defaultButtons">
10
10
  <div v-show="$props.opts?.Add.can"
11
- class="flex cursor-pointer justify-center items-center text-white block bg-blue-600 font-medium rounded text-sm px-4 text-center hover:bg-blue-700 .focus:ring-4.focus:ring-blue-200.dark:focus:ring-blue-900"
11
+ class="flex cursor-pointer justify-center items-center text-white bg-blue-600 font-medium rounded text-sm px-4 text-center hover:bg-blue-700 .focus:ring-4.focus:ring-blue-200.dark:focus:ring-blue-900"
12
12
  @click="add()">
13
13
  <div class="text-xl">
14
14
  +
@@ -30,12 +30,22 @@
30
30
  </div>
31
31
 
32
32
  <!-- ТАБЛИЦА-->
33
- <div class="mt-2 table w-full ">
33
+ <div class="mt-2 table table-fixed w-full ">
34
34
 
35
35
  <!-- ЗАГОЛОВКИ СТОЛБЦОВ-->
36
36
  <div class="table-header-group">
37
- <div v-for="column in Table.columns" v-show="column.Table.isShow" :key="'cheader_' + column"
38
- class="table-cell border-r border-r-slate-100 px-2">
37
+
38
+ <!-- ЧЕКБОКСЫ -->
39
+ <div class="table-cell w-[65px] align-middle">
40
+ <label class="checkbox" v-if="Table.opts.rowSelectors">
41
+ <input type='checkbox' @change="CheckboxSelectionChanged($event, true)">
42
+ <span class='indicator'></span>
43
+ </label>
44
+ </div>
45
+
46
+ <div v-for="column in Table.columns" v-show="column.Table.isShow" :key="'cheader_' + column.name"
47
+ :class="' defaultHeader ' + column.Table.classesHeader"
48
+ class=" table-cell align-middle border-r border-r-slate-100 px-2">
39
49
  <span>{{ column.title !== '' ? column.title :
40
50
  column.name }}</span>
41
51
  </div>
@@ -55,10 +65,23 @@
55
65
  <div class="table-row-group">
56
66
 
57
67
  <template v-for="(row) in (Table.Rows.rows)">
58
- <div :key="'row_' + (row as any).id" class="table-row cursor-pointer hover:bg-slate-100" v-if="true">
59
- <div v-for="column in Table.columns" v-show="column.Table.isShow" :key="'tc_' + column"
60
- class="table-cell border-r border-r-slate-100 px-2 last:border-r-0 last:pr-0"
61
- @click="columnClick(row, column)">
68
+ <div :key="'row_' + (row as any).id" class="defaultRow table-row cursor-pointer hover:bg-slate-100" v-if="true">
69
+
70
+ <!-- ЧЕКБОКСЫ -->
71
+ <div class="table-cell align-middle">
72
+ <label class="checkbox" v-if="Table.opts.rowSelectors">
73
+ <input type='checkbox' v-model="Table.RowsParams[(row as any)[primaryKey]].selected"
74
+ @change="CheckboxSelectionChanged($event, false)">
75
+ <span class='indicator'></span>
76
+ </label>
77
+ </div>
78
+
79
+ <div v-for="column in Table.columns" v-show="column.Table.isShow" :key="'tc_' + column.name"
80
+ :class="' defaultCell ' + column.Table.classes"
81
+ class="table-cell align-middle border-r border-r-slate-100 px-2 last:border-r-0 last:pr-0"
82
+ @click="columnClick(row, column)"
83
+ :style="(column.Table.width === null ? '' : 'width:' + column.Table.width + 'px')">
84
+
62
85
  <span v-if="!column.Table.isRawValue">{{
63
86
  column.Table.value(row, column) }}</span>
64
87
  <span v-else v-html="column.Table.value(row, column)"></span>
@@ -75,7 +98,9 @@
75
98
  </div>
76
99
  </div>
77
100
  <div :key="'row_slot_' + (row as any).id" v-if="opts.onRowClickOpenSlot && !isRowCollapsed(row)">
78
- <slot name="RowSubSlot" :row="row" />
101
+ <div class="table-cell no-wrap-cell">
102
+ <slot name="RowSubSlot" :row="row" />
103
+ </div>
79
104
  </div>
80
105
  </template>
81
106
  </div>
@@ -179,12 +204,12 @@
179
204
  <!-- КНОПКИ СОХРАНЕНИЯ-->
180
205
  <div class="flex w-full mt-3 mb-2 justify-between items-center">
181
206
  <div v-show="$props.opts?.Add.can"
182
- class="cursor-pointer ml-2 text-lg py-2 text-white block bg-gray-400 font-medium rounded text-sm px-4 text-center hover:bg-blue-700 focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-900"
207
+ class="cursor-pointer ml-2 text-lg py-2 text-white block bg-gray-400 font-medium rounded px-4 text-center hover:bg-blue-700 focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-900"
183
208
  @click="Table.OpenedRow = null; FlameTableModal?.close()">
184
209
  Отмена
185
210
  </div>
186
211
  <div
187
- class="cursor-pointer ml-2 text-lg py-2 mr-3 text-white block bg-blue-600 font-medium rounded text-sm px-4 text-center hover:bg-blue-700 focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-900"
212
+ class="cursor-pointer ml-2 text-lg py-2 mr-3 text-white block bg-blue-600 font-medium rounded px-4 text-center hover:bg-blue-700 focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-900"
188
213
  @click=" SaveTable()">
189
214
  {{ Table.mode === 'add' ? 'Добавить' : 'Сохранить' }}
190
215
  </div>
@@ -396,10 +421,106 @@ export default defineComponent({
396
421
  }
397
422
  }
398
423
  },
424
+
425
+ CheckboxSelectionChanged(event: any, all: boolean = false) {
426
+ this.Table.getSelectedRows();
427
+ if (all === true)
428
+ for (const key in this.Table.RowsParams) {
429
+ this.Table.RowsParams[key].selected = event.target.checked
430
+ }
431
+ }
399
432
  },
400
433
 
401
434
  })
402
435
 
403
436
  </script>
404
437
 
405
- <style scoped lang="scss"></style>
438
+ <style scoped lang="scss">
439
+ .no-wrap-cell {
440
+ white-space: nowrap !important;
441
+ }
442
+
443
+ .defaultHeader {
444
+ color: rgba(55, 53, 47, 0.65);
445
+ font-size: 14px;
446
+ line-height: 16.8px;
447
+ font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
448
+ }
449
+
450
+ .defaultRow {
451
+ color: rgb(55, 53, 47);
452
+ font-size: 14px;
453
+ line-height: 16.8px;
454
+ font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
455
+ border: 1px solid rgb(233, 233, 231);
456
+ }
457
+
458
+ // ЧЕКБОКСЫ
459
+ $black: #2D3137;
460
+ $blue: #3785BC;
461
+ $green: #329E78;
462
+ $grey: #D6D6D6;
463
+ $red: #DD3C3A;
464
+ $white: #FFFFFF;
465
+
466
+ $border-radius: 3px;
467
+
468
+ @mixin checkbox($color) {
469
+ margin-right: 1rem;
470
+ padding-left: 1.75rem;
471
+ position: relative;
472
+ -webkit-user-select: none;
473
+ -moz-user-select: none;
474
+ -ms-user-select: none;
475
+ user-select: none;
476
+
477
+ input[type="checkbox"] {
478
+ position: absolute;
479
+ opacity: 0;
480
+
481
+ &:focus~span {
482
+ border: 2px solid lighten($black, 50%);
483
+ }
484
+
485
+ &:focus:checked~span {
486
+ border: 2px solid darken($color, 15%);
487
+ }
488
+
489
+ &:checked~span {
490
+ color: $white;
491
+ background: $color url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHdpZHRoPSIxMiIgaGVpZ2h0PSI5IiB2aWV3Qm94PSIwIDAgMTIgOSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4NCiAgPHBhdGggZD0iTTQuNTc1IDguOTc3cy0uNDA0LS4wMDctLjUzNi0uMTY1TC4wNTcgNS42NGwuODI5LTEuMjI3TDQuNDcgNy4yNjggMTAuOTIxLjA4NmwuOTIzIDEuMTAzLTYuODYzIDcuNjRjLS4xMzQtLjAwMy0uNDA2LjE0OC0uNDA2LjE0OHoiIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPg0KPC9zdmc+) 50% 40% no-repeat;
492
+ border: 2px solid $color;
493
+ }
494
+
495
+ }
496
+
497
+ span {
498
+ border-radius: $border-radius;
499
+ position: absolute;
500
+ left: 50%;
501
+ top: 50%;
502
+ transform: translate(-50%, -50%);
503
+ width: 1.09rem;
504
+ height: 1.09rem;
505
+ background-color: lighten($black, 65%);
506
+ border: 1px solid lighten($black, 65%);
507
+ pointer-events: none;
508
+ -webkit-user-select: none;
509
+ -moz-user-select: none;
510
+ -ms-user-select: none;
511
+ user-select: none;
512
+ }
513
+ }
514
+
515
+ label.checkbox {
516
+ @include checkbox($green);
517
+
518
+ &.blue {
519
+ @include checkbox($blue);
520
+ }
521
+
522
+ &.red {
523
+ @include checkbox($red);
524
+ }
525
+ }
526
+ </style>
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="fc flex-wrap">
3
- <div v-for="(col) in props.columns" :key="col.name" v-show="col.Filter.isShow">
3
+ <div v-for="(col) in props.columns" :key="col.name" v-show="col.Filter.isShow" :class="col.Filter.classes">
4
4
 
5
5
  <!-- ТЕКСТ -->
6
6
  <div class="fc flex-col">
@@ -12,11 +12,17 @@
12
12
  <div v-if="col.Filter.type === 'selector'">
13
13
  <select class="outline-none border border-slate-500 px-2 py-1 mx-2" :placeholder="col.title ?? col.name"
14
14
  @change="update()" v-model="col.Filter.valueString">
15
- <option v-for="item in col.Selector.values" :key="item[0]">
16
-
15
+ <option v-for="item in col.Selector.values" :key="item[0]" value="">
16
+ {{ item[1] }}
17
17
  </option>
18
18
  </select>
19
19
  </div>
20
+ <div v-if="col.Filter.type === 'date' || col.Filter.type === 'daterange'">
21
+ <Datepicker v-if="col.Filter.type === 'date'" v-model="col.Filter.valueString" :auto-apply="true"
22
+ @update:model-value="update()" :teleport="true"></Datepicker>
23
+ <Datepicker v-if="col.Filter.type === 'daterange'" v-model="col.Filter.valueRange" :range="true"
24
+ :auto-apply="true" @update:model-value="update()" :teleport="true" style="z-index: 99999;"></Datepicker>
25
+ </div>
20
26
  </div>
21
27
 
22
28
  </div>
@@ -32,6 +38,7 @@ import TableOpts from './TableOpts';
32
38
  import { Column } from './Columns';
33
39
  //import { TableFilter } from './TableOpts.js';
34
40
  import FlameTable from './FlameTable';
41
+ import Datepicker from '@vuepic/vue-datepicker';
35
42
 
36
43
  // Глобальное хранилище и роуты
37
44
  const store = storeFile(), router = useRouter(), route = useRoute();
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <!-- Это селектор c мультивыбором -->
3
+ <div>
4
+
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts" generic="T">
9
+ import { onMounted, reactive, ref, defineProps } from '@vue/runtime-core'; import type { Ref } from 'vue'; import { storeFile } from "@/store"; import { useRoute, useRouter } from 'vue-router'; import REST from "flamerest"
10
+
11
+ // Иконки
12
+ import { XCircleIcon } from '@icons/24/solid'
13
+ import TableOpts from './TableOpts';
14
+ import { Column } from './Columns';
15
+ //import { TableFilter } from './TableOpts.js';
16
+ import FlameTable from './FlameTable';
17
+ import Datepicker from '@vuepic/vue-datepicker';
18
+
19
+ // Глобальное хранилище и роуты
20
+ const store = storeFile(), router = useRouter(), route = useRoute();
21
+
22
+ // Локальное состояние компонента
23
+ const state = reactive({
24
+ data: {}
25
+ })
26
+
27
+ // Входящие данные компонента
28
+ const props = defineProps<{
29
+ columns: { [key: string]: Column; },
30
+ table: FlameTable<any>,
31
+ }>()
32
+
33
+ // Примонтировано
34
+ onMounted(async () => {
35
+
36
+ })
37
+
38
+
39
+ const update = () => {
40
+
41
+ props.table.update();
42
+
43
+ }
44
+
45
+ </script>
46
+
47
+ <style scoped lang="scss"></style>
@@ -11,6 +11,11 @@ export default class TableOpts {
11
11
  */
12
12
  public autoload: boolean = true;
13
13
 
14
+ /**
15
+ * Добавить колонку выбора записей галочками
16
+ */
17
+ public rowSelectors: boolean = true;
18
+
14
19
  /**
15
20
  * Колонки
16
21
  */
@@ -1,5 +1,6 @@
1
1
  export default class TableRowParams {
2
2
 
3
3
  public collapsed: boolean = true;
4
+ public selected: boolean = false;
4
5
 
5
6
  }