@tripup-company/element-ui-extended 0.0.8 → 0.0.12

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tripup-company/element-ui-extended",
3
- "version": "0.0.8",
3
+ "version": "0.0.12",
4
4
  "main": "./dist/element-ui-extended.umd.js",
5
5
  "scripts": {
6
6
  "serve": "vue-cli-service serve",
package/src/App.vue CHANGED
@@ -1,6 +1,12 @@
1
1
  <template>
2
2
  <div id="app">
3
- <composite-table :fields="fields" :filters="filters" :filters-top="filtersTop" :repository="repository"></composite-table>
3
+ <composite-table
4
+ :storageKey="'Project_name'"
5
+ :fields="fields"
6
+ :filters="filters"
7
+ :top-filter="topFilter"
8
+ :repository="repository"
9
+ ></composite-table>
4
10
  <img alt="Vue logo" src="./assets/logo.png" />
5
11
  </div>
6
12
  </template>
@@ -9,35 +15,39 @@
9
15
  import { Component, Vue } from "vue-property-decorator";
10
16
  import CompositeTable from "@/components/CompositeTable/index.vue";
11
17
  import filters from "./filters";
12
- import filtersTop from "./filters-top";
18
+ import topFilter from "./topFilter";
13
19
  import repository from "./repositories/contacts-repository";
14
20
  @Component({
15
21
  components: { CompositeTable },
16
22
  data: function () {
17
- let repo = new repository('', '/test', null);
23
+ let repo = new repository("", "/test", null);
18
24
  return {
19
25
  filters: filters,
20
- filtersTop: filtersTop,
26
+ topFilter: topFilter,
21
27
  repository: repo,
22
28
  fields: [
23
- {
24
- prop: 'full_name', label: 'Full Name',
25
- formatter: row => {
26
- return row.first_name + ' ' + row.last_name;
29
+ {
30
+ prop: "full_name",
31
+ label: "Full Name",
32
+ formatter: (row) => {
33
+ return row.first_name + " " + row.last_name;
34
+ },
27
35
  },
28
- },
29
- {
30
- prop: 'email', label: 'Email',
31
- },
32
- {
33
- prop: 'phone', label: 'Phone',
34
- },
35
- {
36
- prop: 'created_at', label: 'Created at',
37
- },
38
- ],
39
- }
40
- }
36
+ {
37
+ prop: "email",
38
+ label: "Email",
39
+ },
40
+ {
41
+ prop: "phone",
42
+ label: "Phone",
43
+ },
44
+ {
45
+ prop: "created_at",
46
+ label: "Created at",
47
+ },
48
+ ],
49
+ };
50
+ },
41
51
  })
42
52
  export default class App extends Vue {}
43
53
  </script>
@@ -1,18 +1,17 @@
1
1
  <template>
2
2
  <div v-loading="loading" class="composite-table">
3
3
  <slot>
4
- <slot name="top-filter" v-bind="{ filtersTop, search }">
5
- <generic-top-filter
6
- v-if="filtersTop.length"
7
- :filters="filtersTop"
8
- :search="search"
9
- @apply:filter="handleApplyFilter"
10
- @reset:filter="handleResetFilter"
11
- />
12
- </slot>
13
-
14
4
  <el-row :gutter="20">
15
5
  <el-col :span="18">
6
+ <slot name="quick-search-filter" v-bind="{ topFilter, search }">
7
+ <quick-search-filter
8
+ v-if="topFilter"
9
+ :filter="topFilter"
10
+ :search="topSearch"
11
+ @apply:filter="handleApplyTopFilter"
12
+ @reset:filter="handleResetTopFilter"
13
+ />
14
+ </slot>
16
15
  <slot name="table" v-bind="{ fields, data }">
17
16
  <generic-table
18
17
  :fields="fields"
@@ -58,10 +57,11 @@ import GenericTable from "@/components/GenericTable";
58
57
  import ListQueryService from "@/services/list-query-service";
59
58
  import { LocalStorageService } from "@/services/local-storage-service";
60
59
  import MetaModel from "@/models/meta-model";
61
- import GenericTopFilter from "@/components/GenericFilters/GenericTopFilter";
60
+ import QuickSearchFilter from "@/components/GenericFilters/QuickSearchFilter";
61
+ import FilterConverter from "../GenericFilters/filter-convertor";
62
62
  export default {
63
63
  components: {
64
- GenericTopFilter,
64
+ QuickSearchFilter,
65
65
  GenericFilter,
66
66
  GenericTable,
67
67
  GenericPaginator,
@@ -82,70 +82,91 @@ export default {
82
82
  default: () => [],
83
83
  type: Array,
84
84
  },
85
- filtersTop: {
86
- default: () => [],
87
- type: Array,
85
+ topFilter: {
86
+ default() {
87
+ return {};
88
+ },
89
+ type: Object,
88
90
  },
89
91
  filters: {
90
92
  default: () => [],
91
93
  type: Array,
92
94
  },
93
95
  includes: {
94
- default: '--',
96
+ default: "--",
97
+ type: String,
98
+ },
99
+ storageKey: {
100
+ default: "storage.key",
95
101
  type: String,
96
102
  },
97
103
  },
98
104
  data: function () {
99
- const localStorage = new LocalStorageService();
105
+ const localStorage = new LocalStorageService(this.storageKey);
100
106
  const listQueryService = new ListQueryService(
101
107
  this.$route ? this.$route.name : "storage.key",
102
108
  localStorage
103
109
  );
110
+ const filterConvertor = new FilterConverter();
104
111
  let search = {};
112
+ let topSearch = {};
105
113
  for (const column of this.filters) {
106
114
  search[column.name] = {
107
115
  operator: "",
108
116
  value: "",
109
117
  };
110
118
  }
111
- for (const column of this.filtersTop) {
112
- search[column.name] = {
113
- position: "top",
119
+ if (this.topFilter) {
120
+ topSearch[this.topFilter.name] = {
114
121
  value: "",
122
+ operator: this.topFilter.operator,
115
123
  };
116
124
  }
125
+
117
126
  search = Object.assign(search, listQueryService.getListQuery().search);
127
+ topSearch = Object.assign(
128
+ topSearch,
129
+ listQueryService.getListQuery().topSearch
130
+ );
118
131
  return {
119
132
  loading: false,
120
133
  filter: {},
121
134
  data: [],
122
135
  search: search,
123
- meta: Object.assign(
124
- new MetaModel(),
125
- listQueryService.getListQuery().meta
126
- ),
136
+ topSearch: topSearch,
137
+ filterConvertor: filterConvertor,
138
+ meta: listQueryService.getListQuery().meta,
139
+ metaModel: new MetaModel(),
127
140
  listQueryService: listQueryService,
128
141
  };
129
142
  },
130
143
  computed: {
144
+ queryFilter() {
145
+ const query = {
146
+ page: this.meta.page,
147
+ limit: this.meta.limit,
148
+ };
149
+ const filter = this.filterConvertor.applyFilter({
150
+ ...this.search,
151
+ ...this.topSearch,
152
+ });
153
+ return { ...query, ...filter };
154
+ },
131
155
  currentPage() {
132
- if (this.data.meta?.pagination) {
133
- return this.data.meta.pagination.current_page;
156
+ if (this.meta) {
157
+ return this.meta.page;
134
158
  }
135
159
  return 0;
136
160
  },
137
161
  total() {
138
- if (this.data.meta?.pagination) {
139
- return this.data.meta.pagination.total;
162
+ if (this.metaModel?.pagination) {
163
+ return this.metaModel.pagination.total;
140
164
  }
141
165
  return 0;
142
166
  },
143
167
  limit() {
144
- if (this.data.meta?.pagination) {
145
- return this.data.meta.pagination.per_page;
146
- }
147
- if (this.listQueryService.getListQuery().meta?.limit) {
148
- return this.listQueryService.getListQuery().meta?.limit;
168
+ if (this.meta) {
169
+ return this.meta.limit;
149
170
  }
150
171
  return 10;
151
172
  },
@@ -158,11 +179,11 @@ export default {
158
179
  this.loading = true;
159
180
  try {
160
181
  const response = await this.repository.all(
161
- this.listQueryService.getListQuery(),
182
+ this.queryFilter,
162
183
  this.includes
163
184
  );
164
185
  this.data = response.data;
165
- Vue.set(this.data, "meta", response.meta);
186
+ Vue.set(this, "metaModel", response.meta);
166
187
  } catch (e) {
167
188
  this.$message.error(e.message);
168
189
  }
@@ -179,7 +200,7 @@ export default {
179
200
  page: this.listQueryService.getListQuery().meta.page,
180
201
  },
181
202
  });
182
- this.meta.pagination.per_page = val;
203
+ Vue.set(this.meta, "limit", val);
183
204
  this.fetch();
184
205
  },
185
206
  handleCurrentChange(val) {
@@ -189,34 +210,39 @@ export default {
189
210
  limit: this.listQueryService.getListQuery().meta.limit,
190
211
  },
191
212
  });
192
- this.meta.pagination.current_page = val;
213
+ Vue.set(this.meta, "page", val);
193
214
  this.fetch();
194
215
  },
195
- handleFilterChange(val) {
196
- this.filter = val;
197
- this.meta.pagination.current_page = 1;
198
- this.fetch();
216
+ handleFilterChange() {
217
+ this.handleCurrentChange(1);
199
218
  },
200
- handleApplyFilter(filters) {
219
+ handleApplyFilter() {
201
220
  this.listQueryService.updateListQuery({ search: this.search });
202
- this.handleFilterChange(filters);
221
+ this.handleFilterChange();
203
222
  },
204
223
  handleResetFilter() {
205
224
  for (const column in this.search) {
206
- if (this.search[column].position === "top") {
207
- this.search[column] = Object.assign(this.search[column], {
208
- value: "",
209
- });
210
- } else {
211
- this.search[column] = Object.assign(this.search[column], {
212
- operator: "",
213
- value: "",
214
- });
215
- }
225
+ this.search[column] = Object.assign(this.search[column], {
226
+ operator: "",
227
+ value: "",
228
+ });
216
229
  }
217
230
  this.listQueryService.updateListQuery({ search: {} });
218
231
  this.handleFilterChange({});
219
232
  },
233
+ handleApplyTopFilter() {
234
+ this.listQueryService.updateListQuery({ topSearch: this.topSearch });
235
+ this.handleFilterChange();
236
+ },
237
+ handleResetTopFilter() {
238
+ for (const column in this.topSearch) {
239
+ this.topSearch[column] = Object.assign(this.topSearch[column], {
240
+ value: "",
241
+ });
242
+ }
243
+ this.listQueryService.updateListQuery({ topSearch: {} });
244
+ this.handleFilterChange({});
245
+ },
220
246
  },
221
247
  };
222
248
  </script>
@@ -2,28 +2,66 @@
2
2
  <el-row class="m-b-10">
3
3
  <el-row>
4
4
  <el-col :lg="4" :md="4" :sm="4" :xs="4">
5
- <el-checkbox v-model="showFilter"><span>{{ column.label }}</span></el-checkbox>
5
+ <el-checkbox v-model="showFilter"
6
+ ><span>{{ column.label }}</span></el-checkbox
7
+ >
6
8
  </el-col>
7
9
  </el-row>
8
10
  <el-row v-if="showFilter" class="m-t-5">
9
- <el-col :span="24" class="p-b-10">
11
+ <el-col v-if="operators.length !== 1" :span="24" class="p-b-10">
10
12
  <el-select v-model="search.operator" placeholder="Select">
11
- <el-option v-for="(operator) in column.type==='string' ? stringOperators : enumOperators" :key="operator.value" :value="operator.value" :label="operator.label" />
13
+ <el-option
14
+ v-for="operator in operators"
15
+ :key="operator.value"
16
+ :label="operator.label"
17
+ :value="operator.value"
18
+ />
12
19
  </el-select>
13
20
  </el-col>
14
21
  <el-col :span="24">
15
- <el-input v-if="column.type==='string'" v-show="!isDisableInput(search.operator)" v-model="search.value" />
16
- <el-select v-else v-model="search.value" placeholder="Select" :multiple="isMultiple">
17
- <el-option v-for="(label, value) in (column.type==='enum' ? column.values : boolValues)" :key="value" :value="value" :label="label" />
22
+ <el-input
23
+ v-if="column.type === 'string'"
24
+ v-show="!isDisableInput(search.operator)"
25
+ v-model="search.value"
26
+ />
27
+ <el-date-picker
28
+ v-else-if="column.type === 'date'"
29
+ v-model="search.value"
30
+ class="w-100"
31
+ end-placeholder="To"
32
+ format="dd.MM.yy"
33
+ placeholder="Pick a day"
34
+ range-separator="-"
35
+ start-placeholder="From"
36
+ type="daterange"
37
+ value-format="yyyy-MM-dd"
38
+ />
39
+ <el-select
40
+ refs="select"
41
+ v-else
42
+ v-model="search.value"
43
+ :multiple="isMultiple"
44
+ placeholder="Select"
45
+ :filterable="filterable"
46
+ :remote="remote"
47
+ :remote-method="remoteMethodHandler"
48
+ :loading="loading"
49
+ clearable
50
+ @change="updateSearch"
51
+ >
52
+ <el-option
53
+ v-for="item in selectListLocal"
54
+ :key="item[selectKey]"
55
+ :label="item[selectLabel]"
56
+ :value="item[selectValue]"
57
+ />
18
58
  </el-select>
19
59
  </el-col>
20
60
  </el-row>
21
61
  </el-row>
22
62
  </template>
23
-
24
63
  <script>
25
64
  export default {
26
- name: "FilterRow",
27
65
  props: {
28
66
  column: {
29
67
  type: Object,
@@ -38,67 +76,123 @@ export default {
38
76
  },
39
77
  },
40
78
  },
41
- computed: {
42
- isMultiple() {
43
- return this.column.is_multiple ? this.column.is_multiple : false;
44
- },
45
- },
46
79
  data() {
47
80
  return {
48
- showFilter: this.search.operator !== '',
81
+ loading: false,
82
+ selectKey: this.column.selectKey ?? "key",
83
+ selectLabel: this.column.selectLabel ?? "label",
84
+ selectValue: this.column.selectValue ?? "key",
85
+ filterable: this.column.filterable ?? false,
86
+ remote: this.column.remote ?? false,
87
+ remoteMethod: this.column.remoteMethod ?? null,
88
+ selectListLocal: this.search.selectList
89
+ ? this.search.selectList
90
+ : this.column.type === "enum"
91
+ ? this.column.values
92
+ : this.boolValues,
93
+ showFilter: this.search.operator !== "",
49
94
  stringOperators: [
50
- { 'value': 'equal', 'label': 'is equal' },
51
- { 'value': 'not_equal', 'label': 'is not equal' },
52
- { 'value': 'contains', 'label': 'contains' },
53
- { 'value': 'not_contains', 'label': 'doesn’t contain' },
54
- { 'value': 'is_null', 'label': 'is empty' },
55
- { 'value': 'is_not_null', 'label': 'is not empty' },
56
- { 'value': 'start_with', 'label': 'begins with' },
57
- { 'value': 'end_with', 'label': 'ends with' },
58
- ],
59
- disabledInputOperations: [
60
- 'is_null',
61
- 'is_not_null',
62
- ],
63
- enumOperators: [
64
- { 'value': 'equal', 'label': 'is' },
65
- { 'value': 'in', 'label': 'in' },
95
+ { value: "equal", label: "is equal" },
96
+ { value: "not_equal", label: "is not equal" },
97
+ { value: "contains", label: "contains" },
98
+ { value: "not_contains", label: "doesn’t contain" },
99
+ { value: "is_null", label: "is empty" },
100
+ { value: "is_not_null", label: "is not empty" },
101
+ { value: "start_with", label: "begins with" },
102
+ { value: "end_with", label: "ends with" },
66
103
  ],
104
+ disabledInputOperations: ["is_null", "is_not_null"],
105
+ enumOperators: [{ value: "equal", label: "is" }],
106
+ enumOperatorsMultiple: [{ value: "in", label: "in" }],
107
+ dateOperators: [{ value: "between", label: "between" }],
67
108
  boolValues: {
68
- null: 'empty',
69
- true: 'true',
70
- false: 'false',
109
+ null: "empty",
110
+ true: "true",
111
+ false: "false",
71
112
  },
72
113
  };
73
114
  },
115
+ computed: {
116
+ operators() {
117
+ let operators = [];
118
+ switch (this.column.type) {
119
+ case "string":
120
+ operators = this.stringOperators;
121
+ break;
122
+ case "enum":
123
+ if (this.column.is_multiple) {
124
+ operators = this.enumOperatorsMultiple;
125
+ } else {
126
+ operators = this.enumOperators;
127
+ }
128
+ break;
129
+ case "date":
130
+ operators = this.dateOperators;
131
+ break;
132
+ }
133
+ return operators;
134
+ },
135
+ isMultiple() {
136
+ return this.column.is_multiple ? this.column.is_multiple : false;
137
+ },
138
+ remoteMethodHandler: {
139
+ get() {
140
+ if (this.remoteMethod !== null) {
141
+ return this.remoteCall;
142
+ }
143
+ return null;
144
+ },
145
+ },
146
+ },
74
147
  watch: {
75
148
  showFilter() {
76
149
  if (this.showFilter === false) {
77
- this.search.operator = '';
78
- this.search.value = '';
150
+ this.search.operator = "";
151
+ this.search.value = "";
152
+ } else if (this.search.operator === "" && this.operators.length === 1) {
153
+ this.search.operator = this.operators[0].value;
79
154
  }
80
155
  },
81
- search: {
82
- handler: function(newValue) {
83
- if (newValue.operator === '') {
84
- this.showFilter = false;
85
- }
86
- },
87
- deep: true,
156
+ search() {
157
+ if (this.search.operator === "") {
158
+ this.showFilter = false;
159
+ }
88
160
  },
89
161
  },
162
+ mounted() {
163
+ if (this.operators.length === 1) {
164
+ // this.search.operator = this.operators[0].value;
165
+ }
166
+ },
90
167
  methods: {
91
168
  isDisableInput(operator) {
92
- const disable = this.disabledInputOperations.indexOf(operator) !== -1;
169
+ const disable = this.disabledInputOperations.includes(operator);
93
170
  if (disable) {
94
- this.search.value = '';
171
+ this.search.value = "";
95
172
  }
96
173
  return disable;
97
174
  },
175
+ async remoteCall(query) {
176
+ this.loading = true;
177
+ const response = await this.remoteMethod.all({
178
+ search: this.selectLabel + ":" + query,
179
+ searchFields: this.selectLabel + ":like",
180
+ });
181
+ this.selectListLocal = response.data;
182
+ this.search["selectList"] = response.data;
183
+ this.loading = false;
184
+ },
185
+ updateSearch(key) {
186
+ if (key && this.remote) {
187
+ const obj = { [this.selectKey]: key };
188
+ for (const item of this.selectListLocal) {
189
+ if (item[this.selectKey] === key) {
190
+ obj[this.selectLabel] = item[this.selectLabel];
191
+ this.search.selectList = [obj];
192
+ }
193
+ }
194
+ }
195
+ },
98
196
  },
99
- }
197
+ };
100
198
  </script>
101
-
102
- <style scoped>
103
-
104
- </style>
@@ -0,0 +1,41 @@
1
+ <template>
2
+ <el-row class="m-b-20">
3
+ <el-col v-if="filter">
4
+ <el-input
5
+ v-if="filter.type === 'string'"
6
+ v-model="search[filter.name].value"
7
+ clearable
8
+ @clear="resetFilter"
9
+ @keyup.enter.native="applyFilter"
10
+ />
11
+ </el-col>
12
+ </el-row>
13
+ </template>
14
+
15
+ <script>
16
+ export default {
17
+ name: "QuickSearchFilter",
18
+ props: {
19
+ filter: {
20
+ type: Object,
21
+ default: () => {
22
+ return {};
23
+ },
24
+ },
25
+ search: {
26
+ type: Object,
27
+ default: () => {
28
+ return {};
29
+ },
30
+ },
31
+ },
32
+ methods: {
33
+ applyFilter() {
34
+ this.$emit("apply:filter");
35
+ },
36
+ resetFilter() {
37
+ this.$emit("reset:filter");
38
+ },
39
+ },
40
+ };
41
+ </script>
@@ -42,7 +42,6 @@ export default {
42
42
  },
43
43
  methods: {
44
44
  pageChange (val) {
45
- debugger;
46
45
  this.$emit('page:change', val);
47
46
  },
48
47
  sizeChange(val) {
@@ -3,14 +3,36 @@
3
3
  <el-table :data="data" border @sort-change="sortChange">
4
4
  <template v-for="field in fields">
5
5
  <template v-if="field.callback">
6
- <el-table-column :key="field.prop" v-slot="context" :prop="field.prop" :label="field.label" :width="field.width ? field.width : null" sortable="custom">
7
- <el-link @click="field.callback(field.prop, context.$index, context.row)">
8
- {{ typeof field.formatter === 'function' ? field.formatter(context.row) : context.row[field.prop] }}
6
+ <el-table-column
7
+ :key="field.prop"
8
+ v-slot="context"
9
+ :prop="field.prop"
10
+ :label="field.label"
11
+ :width="field.width ? field.width : null"
12
+ :sortable="field.sortable ? field.sortable : null"
13
+ >
14
+ <el-link
15
+ @click="field.callback(field.prop, context.$index, context.row)"
16
+ >
17
+ {{
18
+ typeof field.formatter === "function"
19
+ ? field.formatter(context.row)
20
+ : context.row[field.prop]
21
+ }}
9
22
  </el-link>
10
23
  </el-table-column>
11
24
  </template>
12
25
  <template v-else>
13
- <el-table-column :formatter="typeof field.formatter === 'function' ? field.formatter : null" :key="field.prop" :prop="field.prop" :label="field.label" :width="field.width ? field.width : null" sortable="custom" />
26
+ <el-table-column
27
+ :formatter="
28
+ typeof field.formatter === 'function' ? field.formatter : null
29
+ "
30
+ :key="field.prop"
31
+ :prop="field.prop"
32
+ :label="field.label"
33
+ :width="field.width ? field.width : null"
34
+ :sortable="field.sortable ? field.sortable : null"
35
+ />
14
36
  </template>
15
37
  </template>
16
38
  </el-table>
@@ -18,7 +40,6 @@
18
40
  </template>
19
41
 
20
42
  <script>
21
-
22
43
  export default {
23
44
  name: "GenericTable",
24
45
  props: {
@@ -44,8 +65,8 @@ export default {
44
65
  },
45
66
  methods: {
46
67
  sortChange(data) {
47
- this.$emit('sort:change', data);
48
- }
49
- }
68
+ this.$emit("sort:change", data);
69
+ },
70
+ },
50
71
  };
51
72
  </script>