flameresttable 1.0.12 → 1.0.14
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/.vscode/launch.json +1 -1
- package/README.md +3 -0
- package/package.json +23 -26
- package/src/App.vue +27 -13
- package/src/Table/Columns.ts +37 -0
- package/src/Table/FlameTable.ts +70 -1
- package/src/Table/Paginator.vue +2 -2
- package/src/Table/Table.vue +49 -22
- package/src/Table/TableFilters.vue +29 -5
- package/src/Table/TableLoadParams.ts +10 -0
- package/src/Table/TableOpts.ts +6 -1
- package/src/Table/TableRowParams.ts +5 -0
- package/src/main.ts +6 -4
- package/src/router.ts +1 -27
package/.vscode/launch.json
CHANGED
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flameresttable",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"main": "./src/plugin.ts",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,38 +15,35 @@
|
|
|
15
15
|
"android": "npm run build && npx cap add android && npx cap sync && npx cap open android"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@vuepic/vue-datepicker": "^
|
|
19
|
-
"flamerest": "^1.0.
|
|
18
|
+
"@vuepic/vue-datepicker": "^7.2.0",
|
|
19
|
+
"flamerest": "^1.0.92",
|
|
20
20
|
"lodash-es": "^4.17.21",
|
|
21
|
-
"pinia": "^2.
|
|
21
|
+
"pinia": "^2.1.7",
|
|
22
22
|
"pug": "github:FlameArt/pug-tailwind-only",
|
|
23
23
|
"pug-lexer": "github:FlameArt/pug-lexer-only",
|
|
24
|
-
"sass": "^1.
|
|
25
|
-
"vue": "^3.
|
|
26
|
-
"vue-router": "^4.
|
|
24
|
+
"sass": "^1.69.5",
|
|
25
|
+
"vue": "^3.3.7",
|
|
26
|
+
"vue-router": "^4.2.5"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@
|
|
30
|
-
"@
|
|
31
|
-
"@
|
|
32
|
-
"@
|
|
33
|
-
"@
|
|
34
|
-
"@
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
37
|
-
"@
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"@vue/compiler-sfc": "^3.2.45",
|
|
41
|
-
"autoprefixer": "^10.4.14",
|
|
42
|
-
"eslint": "^8.38.0",
|
|
29
|
+
"@heroicons/vue": "^2.0.18",
|
|
30
|
+
"@types/lodash-es": "^4.17.10",
|
|
31
|
+
"@types/lodash.merge": "^4.6.8",
|
|
32
|
+
"@types/node": "20.8.9",
|
|
33
|
+
"@typescript-eslint/eslint-plugin": "^6.9.0",
|
|
34
|
+
"@typescript-eslint/parser": "^6.9.0",
|
|
35
|
+
"@vitejs/plugin-vue": "^4.4.0",
|
|
36
|
+
"@volar/vue-language-plugin-pug": "^1.6.5",
|
|
37
|
+
"@vue/compiler-sfc": "^3.3.7",
|
|
38
|
+
"autoprefixer": "^10.4.16",
|
|
39
|
+
"eslint": "^8.52.0",
|
|
43
40
|
"eslint-plugin-vue": "^8.7.1",
|
|
44
|
-
"postcss": "^8.4.
|
|
41
|
+
"postcss": "^8.4.31",
|
|
45
42
|
"postcss-import": "^14.1.0",
|
|
46
|
-
"tailwindcss": "^3.3.
|
|
47
|
-
"typescript": "^
|
|
48
|
-
"vite": "^4.
|
|
49
|
-
"vue-tsc": "^1.
|
|
43
|
+
"tailwindcss": "^3.3.5",
|
|
44
|
+
"typescript": "^5.2.2",
|
|
45
|
+
"vite": "^4.5.0",
|
|
46
|
+
"vue-tsc": "^1.8.22",
|
|
50
47
|
"vue-universal-modal": "^1.1.4"
|
|
51
48
|
},
|
|
52
49
|
"rules": {}
|
package/src/App.vue
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { onMounted, reactive, defineProps } from '@vue/runtime-core'; import { storeFile } from "@/store"; import { useRoute, useRouter } from 'vue-router'; import REST from "flamerest"
|
|
3
3
|
import Table from './Table/Table.vue';
|
|
4
|
+
import { ref } from 'vue';
|
|
5
|
+
import Model from '@models/Testtable';
|
|
6
|
+
import TableOpts from './Table/TableOpts';
|
|
7
|
+
|
|
4
8
|
const store = storeFile(), router = useRouter(), route = useRoute();
|
|
5
9
|
|
|
6
10
|
let notRedirectOnAuthList = [
|
|
@@ -11,23 +15,33 @@ let notRedirectOnAuthList = [
|
|
|
11
15
|
];
|
|
12
16
|
|
|
13
17
|
onMounted(() => {
|
|
14
|
-
|
|
15
|
-
store.authUser(res);
|
|
16
|
-
store.User.isLoaded = true;
|
|
17
|
-
if (res.isAuthorized === false) {
|
|
18
|
-
if (!notRedirectOnAuthList.includes(route.name?.toString() ?? "")) {
|
|
19
|
-
router.push({ name: "Auth" });
|
|
20
|
-
}
|
|
21
|
-
} else {
|
|
22
|
-
// Load state
|
|
23
|
-
// store.projects = REST.get("projects");
|
|
24
|
-
}
|
|
25
|
-
});
|
|
18
|
+
|
|
26
19
|
});
|
|
20
|
+
|
|
21
|
+
const TableComponent = ref<InstanceType<typeof Table>>();
|
|
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.Add.can = true;
|
|
30
|
+
opts.Remove.can = true;
|
|
31
|
+
|
|
32
|
+
opts.onRowClickOpenSlot = true;
|
|
33
|
+
|
|
34
|
+
// Загружаем первичные данные
|
|
35
|
+
Model.all({ sort: ['id'] }).then(r =>
|
|
36
|
+
TableComponent.value?.Table.load(r)
|
|
37
|
+
)
|
|
38
|
+
|
|
27
39
|
</script>
|
|
28
40
|
|
|
29
41
|
<template lang="pug">
|
|
30
|
-
Table
|
|
42
|
+
Table(:model="Model", :opts="opts")
|
|
43
|
+
template(v-slot:RowSubSlot="params")
|
|
44
|
+
| {{ params.row.name }}
|
|
31
45
|
</template>
|
|
32
46
|
|
|
33
47
|
<style>
|
package/src/Table/Columns.ts
CHANGED
|
@@ -53,6 +53,32 @@ export class Column implements IColumn {
|
|
|
53
53
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Это related данные для всех селекторов и внутри таблицы
|
|
58
|
+
*/
|
|
59
|
+
public Selector = {
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Загрузчик значений
|
|
63
|
+
* @returns Array
|
|
64
|
+
*/
|
|
65
|
+
loader: () => [],
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Здесь список готовых значений
|
|
69
|
+
*/
|
|
70
|
+
values: [],
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Здесь можно определить кастомный лоадер при поиске
|
|
74
|
+
* @param row
|
|
75
|
+
* @param col
|
|
76
|
+
* @returns
|
|
77
|
+
*/
|
|
78
|
+
value: (row: any, col: string) => row[col]
|
|
79
|
+
|
|
80
|
+
};
|
|
81
|
+
|
|
56
82
|
/**
|
|
57
83
|
* Настройки фильтра
|
|
58
84
|
*/
|
|
@@ -65,6 +91,14 @@ export class Column implements IColumn {
|
|
|
65
91
|
valueString: "",
|
|
66
92
|
valueRange: { from: '', to: '' },
|
|
67
93
|
|
|
94
|
+
// Тип фильтра
|
|
95
|
+
type: 'text' as "text" | "fixed" | "fulltext" | "number" | "date" | "daterange" | "selector",
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Список значений под выбор
|
|
99
|
+
*/
|
|
100
|
+
select: [],
|
|
101
|
+
|
|
68
102
|
// Минимальное число символов в строке фильтра, после которого будет произведён запрос
|
|
69
103
|
filterMinSymbolsRequest: 0,
|
|
70
104
|
|
|
@@ -211,6 +245,9 @@ export interface IColumn {
|
|
|
211
245
|
// Показываем ли фильтр
|
|
212
246
|
isShow?: boolean,
|
|
213
247
|
|
|
248
|
+
// Тип фильтра
|
|
249
|
+
type?: "text" | "fixed" | "fulltext" | "number" | "date" | "daterange" | "selector",
|
|
250
|
+
|
|
214
251
|
// Значение
|
|
215
252
|
valueString?: string,
|
|
216
253
|
valueRange?: { from: string, to: string },
|
package/src/Table/FlameTable.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { Rows, SavedObject } from 'flamerest';
|
|
|
3
3
|
import TableOpts from "./TableOpts";
|
|
4
4
|
import { reactive, UnwrapRef } from 'vue';
|
|
5
5
|
import merge from 'lodash-es/merge'
|
|
6
|
+
import ITableLoadParams from './TableLoadParams';
|
|
7
|
+
import TableRowParams from './TableRowParams';
|
|
6
8
|
|
|
7
9
|
// Подгрузчик типа класса
|
|
8
10
|
type Class<T> = new (...args: any[]) => T
|
|
@@ -38,6 +40,11 @@ export default class FlameTable<T> {
|
|
|
38
40
|
*/
|
|
39
41
|
public Rows = reactive({ rows: [] as Array<T> });
|
|
40
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Динамические параметры строк
|
|
45
|
+
*/
|
|
46
|
+
public RowsParams: { [key: string]: TableRowParams } = reactive({});
|
|
47
|
+
|
|
41
48
|
/**
|
|
42
49
|
* Параметры паджинации
|
|
43
50
|
*/
|
|
@@ -109,6 +116,16 @@ export default class FlameTable<T> {
|
|
|
109
116
|
if (rows.data) {
|
|
110
117
|
this.Rows.rows = (rows.data ?? []) as any;
|
|
111
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
|
+
})
|
|
112
129
|
}
|
|
113
130
|
|
|
114
131
|
}
|
|
@@ -121,12 +138,64 @@ export default class FlameTable<T> {
|
|
|
121
138
|
|
|
122
139
|
if (SaveLoadParams !== null) this.opts.LoadParams = SaveLoadParams;
|
|
123
140
|
|
|
124
|
-
|
|
141
|
+
// Дополняем загрузочные параметры фильтрами
|
|
142
|
+
const filters = this.applyFiltersParams();
|
|
143
|
+
|
|
144
|
+
const rows: Rows<T> = await (this.model as any).constructor.all(merge({}, this.opts.LoadParams, filters, { page: this.Pager.page, perPage: this.Pager.perPage }));
|
|
125
145
|
|
|
126
146
|
this.load(rows);
|
|
127
147
|
|
|
128
148
|
}
|
|
129
149
|
|
|
150
|
+
public applyFiltersParams() {
|
|
151
|
+
const customFilters: ITableLoadParams = {
|
|
152
|
+
where: {}
|
|
153
|
+
};
|
|
154
|
+
for (const key in this.columns) {
|
|
155
|
+
const el = this.columns[key].Filter;
|
|
156
|
+
switch (el.type) {
|
|
157
|
+
|
|
158
|
+
// Частичное совпадение
|
|
159
|
+
case 'text':
|
|
160
|
+
|
|
161
|
+
if (el.valueString.trim() === '') continue;
|
|
162
|
+
customFilters.where[key] = ['LIKE', key, el.valueString];
|
|
163
|
+
break;
|
|
164
|
+
|
|
165
|
+
// Фуллтекстовый поиск
|
|
166
|
+
case 'fulltext':
|
|
167
|
+
|
|
168
|
+
if (el.valueString.trim() === '') continue;
|
|
169
|
+
customFilters.where[key] = ['FULLTEXT', key, el.valueString];
|
|
170
|
+
break;
|
|
171
|
+
|
|
172
|
+
// Точное совпадение
|
|
173
|
+
case 'fixed':
|
|
174
|
+
case 'date':
|
|
175
|
+
case 'selector':
|
|
176
|
+
|
|
177
|
+
if (el.valueString.trim() === '') continue;
|
|
178
|
+
customFilters.where[key] = el.valueString;
|
|
179
|
+
|
|
180
|
+
break;
|
|
181
|
+
|
|
182
|
+
// ДИАПАЗОН
|
|
183
|
+
case 'number':
|
|
184
|
+
case 'daterange':
|
|
185
|
+
|
|
186
|
+
if (el.valueRange.from.trim() !== '')
|
|
187
|
+
customFilters.where[key] = ['>=', key, el.valueRange.from];
|
|
188
|
+
if (el.valueRange.to.trim() !== '')
|
|
189
|
+
customFilters.where[key] = ['<=', key, el.valueRange.to];
|
|
190
|
+
|
|
191
|
+
break;
|
|
192
|
+
|
|
193
|
+
default:
|
|
194
|
+
alert('Unknown table filter type');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return customFilters;
|
|
198
|
+
}
|
|
130
199
|
|
|
131
200
|
|
|
132
201
|
public async add(): Promise<SavedObject<T> | null> {
|
package/src/Table/Paginator.vue
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<template lang="pug">
|
|
2
|
-
nav.relative.z-0.w-full.fc.rounded-md.-space-x-px(aria-label='Pagination' @click="")
|
|
2
|
+
nav.relative.z-0.w-full.fc.flex-wrap.rounded-md.-space-x-px(aria-label='Pagination' @click="")
|
|
3
3
|
a.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(href='#' class='hover:bg-gray-50')
|
|
4
4
|
span.sr-only Previous
|
|
5
5
|
// Heroicon name: solid/chevron-left
|
|
6
6
|
svg.h-5.w-5(xmlns='http://www.w3.org/2000/svg' viewbox='0 0 20 20' fill='currentColor' aria-hidden='true')
|
|
7
7
|
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')
|
|
8
8
|
// 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"
|
|
9
|
-
a.bg-white.border-gray-300.text-gray-500.relative.inline-flex.items-center.px-4.py-2.border.text-sm.font-medium(v-for="page in props.table.Pager.count" class="hover:bg-gray-50" :class="props.table.Pager.page === page ? 'z-10 bg-indigo-50 border-indigo-500 text-indigo-600' : ''" @click="goPage(page)")
|
|
9
|
+
a.cursor-pointer.bg-white.border-gray-300.text-gray-500.relative.inline-flex.items-center.px-4.py-2.border.text-sm.font-medium(v-for="page in props.table.Pager.count" class="hover:bg-gray-50" :class="props.table.Pager.page === page ? 'z-10 bg-indigo-50 border-indigo-500 text-indigo-600' : ''" @click="goPage(page)")
|
|
10
10
|
| {{ page }}
|
|
11
11
|
//span.relative.inline-flex.items-center.px-4.py-2.border.border-gray-300.bg-white.text-sm.font-medium.text-gray-700 ...
|
|
12
12
|
a.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(href='#' class='hover:bg-gray-50')
|
package/src/Table/Table.vue
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="mt-0 overflow-x-scroll">
|
|
3
3
|
|
|
4
|
+
<!-- ФИЛЬТРЫ -->
|
|
5
|
+
<TableFilters :columns="Table.columns" :table="Table"></TableFilters>
|
|
6
|
+
|
|
4
7
|
<!-- "ДОБАВИТЬ" И ЧИСЛО ЗАПИСЕЙ-->
|
|
5
8
|
<div class="flex items-center justify-between">
|
|
6
9
|
<slot name="defaultButtons">
|
|
@@ -50,25 +53,29 @@
|
|
|
50
53
|
<!-- СТРОКИ-->
|
|
51
54
|
<div class="table-row-group">
|
|
52
55
|
|
|
53
|
-
<
|
|
54
|
-
class="table-row cursor-pointer hover:bg-slate-100">
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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>{{
|
|
62
|
+
column.Table.value(row, column) }}</span>
|
|
63
|
+
</div>
|
|
64
|
+
<div v-if="opts.Edit.can" class="table-cell border-r border-r-slate-100 px-2 text-center">
|
|
65
|
+
<button class="px-2 py-1 bg-green-600 text-white my-1" @click="edit(row)">
|
|
66
|
+
Изменить
|
|
67
|
+
</button>
|
|
68
|
+
</div>
|
|
69
|
+
<div v-if="opts.Remove.can" class="table-cell border-r border-r-slate-100 px-2 text-center">
|
|
70
|
+
<button class="px-2 py-1 bg-gray-600 opacity-30 text-white my-1" @click="deleteRow(row)">
|
|
71
|
+
Удалить
|
|
72
|
+
</button>
|
|
73
|
+
</div>
|
|
65
74
|
</div>
|
|
66
|
-
<div v-if="opts.
|
|
67
|
-
<
|
|
68
|
-
Удалить
|
|
69
|
-
</button>
|
|
75
|
+
<div :key="'row_slot_' + (row as any).id" v-if="opts.onRowClickOpenSlot && !isRowCollapsed(row)">
|
|
76
|
+
<slot name="RowSubSlot" :row="row" />
|
|
70
77
|
</div>
|
|
71
|
-
</
|
|
78
|
+
</template>
|
|
72
79
|
</div>
|
|
73
80
|
|
|
74
81
|
</div>
|
|
@@ -176,7 +183,7 @@
|
|
|
176
183
|
</div>
|
|
177
184
|
<div
|
|
178
185
|
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"
|
|
179
|
-
@click=" SaveTable()
|
|
186
|
+
@click=" SaveTable()">
|
|
180
187
|
{{ Table.mode === 'add' ? 'Добавить' : 'Сохранить' }}
|
|
181
188
|
</div>
|
|
182
189
|
</div>
|
|
@@ -191,12 +198,13 @@ import { onMounted, reactive, ref, defineProps } from '@vue/runtime-core'; impor
|
|
|
191
198
|
// Иконки
|
|
192
199
|
import { XCircleIcon } from '@icons/24/solid'
|
|
193
200
|
import { computed } from '@vue/reactivity';
|
|
194
|
-
import { Column } from './Columns';
|
|
201
|
+
import { Column, IColumn } from './Columns';
|
|
195
202
|
import { defineComponent } from 'vue';
|
|
196
203
|
import TableOpts from './TableOpts';
|
|
197
204
|
import FlameTable from './FlameTable';
|
|
198
205
|
import ModalVue from './../components/default/Modal.vue';
|
|
199
206
|
import Paginator from './Paginator.vue';
|
|
207
|
+
import TableFilters from './TableFilters.vue';
|
|
200
208
|
type Class<T> = new (...args: any[]) => T;
|
|
201
209
|
|
|
202
210
|
import Datepicker from '@vuepic/vue-datepicker';
|
|
@@ -205,7 +213,7 @@ import { isNumber } from 'lodash';
|
|
|
205
213
|
|
|
206
214
|
|
|
207
215
|
export default defineComponent({
|
|
208
|
-
components: { ModalVue, Paginator, Datepicker },
|
|
216
|
+
components: { ModalVue, Paginator, Datepicker, TableFilters },
|
|
209
217
|
props: {
|
|
210
218
|
rows: {
|
|
211
219
|
default: [] as Array<any>,
|
|
@@ -318,6 +326,22 @@ export default defineComponent({
|
|
|
318
326
|
})
|
|
319
327
|
}
|
|
320
328
|
|
|
329
|
+
const primaryKey = (Table.model as any).constructor.primaryKeys[0];
|
|
330
|
+
|
|
331
|
+
const columnClick = (row: any, column: Column) => {
|
|
332
|
+
if (Table.opts.onRowClickOpenSlot) {
|
|
333
|
+
Table.RowsParams[row[primaryKey]].collapsed = !Table.RowsParams[row[primaryKey]].collapsed
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
if (column?.Table?.click !== undefined)
|
|
337
|
+
column.Table.click(row, column);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const isRowCollapsed = (row: any) => {
|
|
341
|
+
return Table.RowsParams[row[primaryKey]].collapsed
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
|
|
321
345
|
return {
|
|
322
346
|
Table,
|
|
323
347
|
FlameTableModal,
|
|
@@ -327,7 +351,10 @@ export default defineComponent({
|
|
|
327
351
|
SaveTable,
|
|
328
352
|
deleteRow,
|
|
329
353
|
fileUpdated,
|
|
330
|
-
getSelector
|
|
354
|
+
getSelector,
|
|
355
|
+
primaryKey,
|
|
356
|
+
columnClick,
|
|
357
|
+
isRowCollapsed
|
|
331
358
|
}
|
|
332
359
|
|
|
333
360
|
},
|
|
@@ -364,7 +391,7 @@ export default defineComponent({
|
|
|
364
391
|
}
|
|
365
392
|
}
|
|
366
393
|
}
|
|
367
|
-
}
|
|
394
|
+
},
|
|
368
395
|
},
|
|
369
396
|
|
|
370
397
|
})
|
|
@@ -1,13 +1,29 @@
|
|
|
1
|
-
<template
|
|
2
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<div class="fc flex-wrap">
|
|
3
|
+
<div v-for="(col) in props.columns" :key="col.name" v-show="col.Filter.isShow">
|
|
4
|
+
|
|
5
|
+
<!-- ТЕКСТ -->
|
|
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>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
3
16
|
</template>
|
|
4
17
|
|
|
5
|
-
<script setup lang="ts">
|
|
18
|
+
<script setup lang="ts" generic="T">
|
|
6
19
|
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"
|
|
7
20
|
|
|
8
21
|
// Иконки
|
|
9
22
|
import { XCircleIcon } from '@icons/24/solid'
|
|
10
|
-
import
|
|
23
|
+
import TableOpts from './TableOpts';
|
|
24
|
+
import { Column } from './Columns';
|
|
25
|
+
//import { TableFilter } from './TableOpts.js';
|
|
26
|
+
import FlameTable from './FlameTable';
|
|
11
27
|
|
|
12
28
|
// Глобальное хранилище и роуты
|
|
13
29
|
const store = storeFile(), router = useRouter(), route = useRoute();
|
|
@@ -19,7 +35,8 @@ const state = reactive({
|
|
|
19
35
|
|
|
20
36
|
// Входящие данные компонента
|
|
21
37
|
const props = defineProps<{
|
|
22
|
-
|
|
38
|
+
columns: { [key: string]: Column; },
|
|
39
|
+
table: FlameTable<any>,
|
|
23
40
|
}>()
|
|
24
41
|
|
|
25
42
|
// Примонтировано
|
|
@@ -27,6 +44,13 @@ onMounted(async () => {
|
|
|
27
44
|
|
|
28
45
|
})
|
|
29
46
|
|
|
47
|
+
|
|
48
|
+
const update = () => {
|
|
49
|
+
|
|
50
|
+
props.table.update();
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
30
54
|
</script>
|
|
31
55
|
|
|
32
56
|
<style scoped lang="scss"></style>
|
package/src/Table/TableOpts.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Column, IColumn } from './Columns';
|
|
|
2
2
|
|
|
3
3
|
import merge from 'lodash-es/merge'
|
|
4
4
|
import FlameTable from './FlameTable';
|
|
5
|
+
import ITableLoadParams from './TableLoadParams';
|
|
5
6
|
|
|
6
7
|
export default class TableOpts {
|
|
7
8
|
|
|
@@ -18,8 +19,12 @@ export default class TableOpts {
|
|
|
18
19
|
/**
|
|
19
20
|
* Параметры прогрузки
|
|
20
21
|
*/
|
|
21
|
-
public LoadParams = {}
|
|
22
|
+
public LoadParams: ITableLoadParams = {};
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Открывать субслот в таблице при клике
|
|
26
|
+
*/
|
|
27
|
+
public onRowClickOpenSlot: boolean = false;
|
|
23
28
|
|
|
24
29
|
public set(ColumnName: string, mergingOpts: IColumn) {
|
|
25
30
|
// TODO: ЕСТЬ ОШИБКА???
|
package/src/main.ts
CHANGED
|
@@ -6,12 +6,14 @@ import router from "./router";
|
|
|
6
6
|
|
|
7
7
|
import 'vue-universal-modal/dist/index.css'
|
|
8
8
|
import VueUniversalModal from 'vue-universal-modal'
|
|
9
|
+
import REST from 'flamerest';
|
|
9
10
|
|
|
10
11
|
|
|
12
|
+
REST.SERVER = 'http://testrest';
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
createApp(App)
|
|
14
|
-
.use(createPinia())
|
|
15
|
-
.use(router)
|
|
16
|
-
.use(VueUniversalModal, {teleportTarget: '#my-modals',modalComponent: 'CustomModal'})
|
|
17
|
-
.mount('#app')
|
|
16
|
+
.use(createPinia())
|
|
17
|
+
.use(router)
|
|
18
|
+
.use(VueUniversalModal, { teleportTarget: '#my-modals', modalComponent: 'CustomModal' })
|
|
19
|
+
.mount('#app')
|
package/src/router.ts
CHANGED
|
@@ -3,34 +3,8 @@ const routes = [
|
|
|
3
3
|
{
|
|
4
4
|
path: '/',
|
|
5
5
|
name: 'Home',
|
|
6
|
-
component: ()=> import('./pages/Home.vue'),
|
|
6
|
+
component: () => import('./pages/Home.vue'),
|
|
7
7
|
},
|
|
8
|
-
{
|
|
9
|
-
path: '/in',
|
|
10
|
-
name: 'Auth',
|
|
11
|
-
component: ()=> import('./pages/user/Auth.vue'),
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
path: '/signup',
|
|
15
|
-
name: 'Signup',
|
|
16
|
-
component: ()=> import('./pages/user/Signup.vue'),
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
path: '/resetpasswordrequest',
|
|
20
|
-
name: 'ResetPasswordRequest',
|
|
21
|
-
component: ()=> import('./pages/user/ResetPasswordRequest.vue'),
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
path: '/resetpassword',
|
|
25
|
-
name: 'ResetPassword',
|
|
26
|
-
component: ()=> import('./pages/user/ResetPassword.vue'),
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
path: '/mysettings',
|
|
30
|
-
name: 'MySettings',
|
|
31
|
-
component: ()=> import('./pages/user/UserSettings.vue'),
|
|
32
|
-
},
|
|
33
|
-
|
|
34
8
|
|
|
35
9
|
]
|
|
36
10
|
const router = createRouter({
|