@tripup-company/element-ui-extended 0.0.1

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 ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@tripup-company/element-ui-extended",
3
+ "version": "0.0.1",
4
+ "main": "./dist/element-ui-extended.umd.js",
5
+ "scripts": {
6
+ "serve": "vue-cli-service serve",
7
+ "build": "vue-cli-service build",
8
+ "lint": "vue-cli-service lint",
9
+ "build-lib": "vue-cli-service build --target lib src/index.ts"
10
+ },
11
+ "dependencies": {
12
+ "core-js": "^3.6.5",
13
+ "npe": "^1.2.0",
14
+ "vue": "^2.6.11",
15
+ "vue-class-component": "^7.2.3",
16
+ "vue-property-decorator": "^9.1.2"
17
+ },
18
+ "devDependencies": {
19
+ "@typescript-eslint/eslint-plugin": "^4.18.0",
20
+ "@typescript-eslint/parser": "^4.18.0",
21
+ "@vue/cli-plugin-babel": "~4.5.0",
22
+ "@vue/cli-plugin-eslint": "~4.5.0",
23
+ "@vue/cli-plugin-typescript": "~4.5.0",
24
+ "@vue/cli-service": "~4.5.0",
25
+ "@vue/eslint-config-prettier": "^6.0.0",
26
+ "@vue/eslint-config-typescript": "^7.0.0",
27
+ "eslint": "^6.7.2",
28
+ "eslint-plugin-prettier": "^3.3.1",
29
+ "eslint-plugin-vue": "^6.2.2",
30
+ "prettier": "^2.2.1",
31
+ "sass": "^1.26.5",
32
+ "sass-loader": "^8.0.2",
33
+ "typescript": "~4.1.5",
34
+ "vue-template-compiler": "^2.6.11"
35
+ },
36
+ "files": [
37
+ "dist/*",
38
+ "src/**/*.vue"
39
+ ],
40
+ "description": "## Project setup ``` npm install ```",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/tripup-company/element-ui-extended.git"
44
+ },
45
+ "author": "valeriy zhurba",
46
+ "license": "ISC",
47
+ "bugs": {
48
+ "url": "https://github.com/tripup-company/element-ui-extended/issues"
49
+ },
50
+ "homepage": "https://github.com/tripup-company/element-ui-extended#readme"
51
+ }
package/src/App.vue ADDED
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <div id="app">
3
+ <img alt="Vue logo" src="./assets/logo.png" />
4
+ <test />
5
+ </div>
6
+ </template>
7
+
8
+ <script lang="ts">
9
+ import { Component, Vue } from "vue-property-decorator";
10
+ import HelloWorld from "./components/HelloWorld.vue";
11
+ import Test from "./components/Test/index.vue";
12
+ @Component({
13
+ components: {
14
+ HelloWorld,
15
+ Test,
16
+ },
17
+ })
18
+ export default class App extends Vue {}
19
+ </script>
20
+
21
+ <style lang="scss">
22
+ #app {
23
+ font-family: Avenir, Helvetica, Arial, sans-serif;
24
+ -webkit-font-smoothing: antialiased;
25
+ -moz-osx-font-smoothing: grayscale;
26
+ text-align: center;
27
+ color: #2c3e50;
28
+ margin-top: 60px;
29
+ }
30
+ </style>
@@ -0,0 +1,97 @@
1
+ <template>
2
+ <el-row v-if="column.position !== 'top'" class="m-b-10">
3
+ <el-row>
4
+ <el-col :lg="4" :md="4" :sm="4" :xs="4">
5
+ <el-checkbox v-model="showFilter"><span>{{ column.label }}</span></el-checkbox>
6
+ </el-col>
7
+ </el-row>
8
+ <el-row v-if="showFilter" class="m-t-5">
9
+ <el-col :span="24" class="p-b-10">
10
+ <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" />
12
+ </el-select>
13
+ </el-col>
14
+ <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" />
18
+ </el-select>
19
+ </el-col>
20
+ </el-row>
21
+ </el-row>
22
+ </template>
23
+ <script>
24
+ export default {
25
+ props: {
26
+ column: {
27
+ type: Object,
28
+ default() {
29
+ return {};
30
+ },
31
+ },
32
+ search: {
33
+ type: Object,
34
+ default() {
35
+ return {};
36
+ },
37
+ },
38
+ },
39
+ computed: {
40
+ isMultiple() {
41
+ return this.column.is_multiple ? this.column.is_multiple : false;
42
+ },
43
+ },
44
+ data() {
45
+ return {
46
+ showFilter: this.search.operator !== '',
47
+ stringOperators: [
48
+ { 'value': 'equal', 'label': 'is equal' },
49
+ { 'value': 'not_equal', 'label': 'is not equal' },
50
+ { 'value': 'contains', 'label': 'contains' },
51
+ { 'value': 'not_contains', 'label': 'doesn’t contain' },
52
+ { 'value': 'is_null', 'label': 'is empty' },
53
+ { 'value': 'is_not_null', 'label': 'is not empty' },
54
+ { 'value': 'start_with', 'label': 'begins with' },
55
+ { 'value': 'end_with', 'label': 'ends with' },
56
+ ],
57
+ disabledInputOperations: [
58
+ 'is_null',
59
+ 'is_not_null',
60
+ ],
61
+ enumOperators: [
62
+ { 'value': 'equal', 'label': 'is' },
63
+ ],
64
+ boolValues: {
65
+ null: 'empty',
66
+ true: 'true',
67
+ false: 'false',
68
+ },
69
+ };
70
+ },
71
+ watch: {
72
+ showFilter() {
73
+ if (this.showFilter === false) {
74
+ this.search.operator = '';
75
+ this.search.value = '';
76
+ }
77
+ },
78
+ search: {
79
+ handler: function(newValue) {
80
+ if (newValue.operator === '') {
81
+ this.showFilter = false;
82
+ }
83
+ },
84
+ deep: true,
85
+ },
86
+ },
87
+ methods: {
88
+ isDisableInput(operator) {
89
+ const disable = this.disabledInputOperations.indexOf(operator) !== -1;
90
+ if (disable) {
91
+ this.search.value = '';
92
+ }
93
+ return disable;
94
+ },
95
+ },
96
+ };
97
+ </script>
@@ -0,0 +1,83 @@
1
+ <template>
2
+ <el-col v-if="column.position === 'top'" :span="18" class="m-b-20">
3
+ <el-col v-if="column.type !== 'checkbox'" class="m-b-5 p-l-0">
4
+ <label>{{ column.label }}</label>
5
+ </el-col>
6
+ <el-input v-if="column.type==='string'" v-model="search.value" />
7
+ </el-col>
8
+ </template>
9
+ <script>
10
+ export default {
11
+ props: {
12
+ column: {
13
+ type: Object,
14
+ default() {
15
+ return {};
16
+ },
17
+ },
18
+ search: {
19
+ type: Object,
20
+ default() {
21
+ return {};
22
+ },
23
+ },
24
+ },
25
+ data() {
26
+ return {
27
+ loading: false,
28
+ selectKey: this.column.selectKey ?? 'key',
29
+ selectLabel: this.column.selectLabel ?? 'label',
30
+ selectValue: this.column.selectValue ?? 'key',
31
+ filterable: this.column.filterable ?? false,
32
+ remote: this.column.remote ?? false,
33
+ remoteMethod: this.column.remoteMethod ?? null,
34
+ selectListLocal: this.search.selectList ? this.search.selectList : (this.column.type === 'enum' ? this.column.values : this.boolValues),
35
+ };
36
+ },
37
+ computed: {
38
+ isMultiple() {
39
+ return this.column.is_multiple ? this.column.is_multiple : false;
40
+ },
41
+ remoteMethodHandler: {
42
+ get() {
43
+ if (this.remoteMethod !== null) {
44
+ return this.remoteCall;
45
+ }
46
+ return null;
47
+ },
48
+ },
49
+ },
50
+ watch: {
51
+ search() {
52
+ if (this.search.operator === '') {
53
+ this.showFilter = false;
54
+ }
55
+ },
56
+ },
57
+ mounted() {
58
+ if (this.column.operator) {
59
+ this.search.operator = this.column.operator;
60
+ }
61
+ },
62
+ methods: {
63
+ async remoteCall(query) {
64
+ this.loading = true;
65
+ const response = await this.remoteMethod.all({ search: this.selectLabel + ':' + query, searchFields: this.selectLabel + ':like' });
66
+ this.selectListLocal = response.data;
67
+ this.search['selectList'] = response.data;
68
+ this.loading = false;
69
+ },
70
+ updateSearch(key) {
71
+ if (key && this.remote) {
72
+ const obj = { [this.selectKey]: key };
73
+ for (const item of this.selectListLocal) {
74
+ if (item[this.selectKey] === key) {
75
+ obj[this.selectLabel] = item[this.selectLabel];
76
+ this.search.selectList = [obj];
77
+ }
78
+ }
79
+ }
80
+ },
81
+ },
82
+ };
83
+ </script>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <el-card>
3
+ <filter-row
4
+ v-for="(column) in data.filters"
5
+ :key="column.name"
6
+ :column="column"
7
+ :search="search[column.name]"
8
+ />
9
+ <el-button @click="applyFilter">Filter</el-button>
10
+ <el-button @click="resetFilter">Reset filter</el-button>
11
+ </el-card>
12
+ </template>
13
+
14
+ <script>
15
+ import FilterRow from './FilterRow';
16
+ import FilterConverter from './filter-convertor.ts';
17
+ export default {
18
+ name: 'GenericFilter',
19
+ components: { FilterRow },
20
+ inject: ['data', 'actions', 'search'],
21
+ data() {
22
+ const filterConvertor = new FilterConverter();
23
+ return {
24
+ filterConvertor: filterConvertor,
25
+ };
26
+ },
27
+ methods: {
28
+ getFilter() {
29
+ return this.filterConvertor.applyFilter(this.search);
30
+ },
31
+ applyFilter() {
32
+ this.actions.handleApplyFilter();
33
+ },
34
+ resetFilter() {
35
+ this.actions.handleResetFilter();
36
+ },
37
+ },
38
+ };
39
+ </script>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <div class="m-t-15">
3
+ <el-pagination
4
+ :current-page="currentPage"
5
+ :total="total"
6
+ :layout="'total, sizes, prev, pager, next, jumper'"
7
+ @size-change="actions.handleSizeChange"
8
+ @current-change="actions.handleCurrentChange"
9
+ />
10
+ </div>
11
+ </template>
12
+
13
+ <script>
14
+
15
+ export default {
16
+ name: 'GenericPaginator',
17
+ inject: ['data', 'actions'],
18
+ computed: {
19
+ currentPage(){
20
+ if (this.data.meta?.pagination){
21
+ return this.data.meta.pagination.current_page;
22
+ }
23
+ return 0;
24
+ },
25
+ total(){
26
+ if (this.data.meta?.pagination){
27
+ return this.data.meta.pagination.total;
28
+ }
29
+ return 0;
30
+ },
31
+ },
32
+ };
33
+ </script>
34
+
35
+ <style scoped>
36
+
37
+ </style>
@@ -0,0 +1,27 @@
1
+ <template>
2
+ <div>
3
+ <slot :items="data.items" :fields="data.fields">
4
+ <el-table :data="data.items" border>
5
+ <template v-for="field in data.fields">
6
+ <template v-if="field.callback">
7
+ <el-table-column :key="field.prop" v-slot="context" :prop="field.prop" :label="field.label" :width="field.width ? field.width : null">
8
+ <el-link @click="field.callback(field.prop, context.$index, context.row)">
9
+ {{ typeof field.formatter === 'function' ? field.formatter(context.row) : context.row[field.prop] }}
10
+ </el-link>
11
+ </el-table-column>
12
+ </template>
13
+ <template v-else>
14
+ <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" />
15
+ </template>
16
+ </template>
17
+ </el-table>
18
+ </slot>
19
+ </div>
20
+ </template>
21
+
22
+ <script>
23
+ export default {
24
+ name: 'GenericRows',
25
+ inject: ['data'],
26
+ };
27
+ </script>
@@ -0,0 +1,41 @@
1
+ <template>
2
+ <div>
3
+ <filter-top-row
4
+ v-for="(column) in data.filters"
5
+ :key="column.name"
6
+ :column="column"
7
+ :search="search[column.name]"
8
+ />
9
+ <el-col :span="6" class="m-t-20">
10
+ <el-button @click="applyFilter">Filter</el-button>
11
+ <el-button @click="resetFilter">Reset filter</el-button>
12
+ </el-col>
13
+ </div>
14
+ </template>
15
+
16
+ <script>
17
+ import FilterTopRow from './FilterTopRow';
18
+ import FilterConverter from './filter-convertor.ts';
19
+ export default {
20
+ name: 'GenericTopFilter',
21
+ components: { FilterTopRow },
22
+ inject: ['data', 'actions', 'search'],
23
+ data() {
24
+ const filterConvertor = new FilterConverter();
25
+ return {
26
+ filterConvertor: filterConvertor,
27
+ };
28
+ },
29
+ methods: {
30
+ getFilter() {
31
+ return this.filterConvertor.applyFilter(this.search);
32
+ },
33
+ applyFilter() {
34
+ this.actions.handleApplyFilter();
35
+ },
36
+ resetFilter() {
37
+ this.actions.handleResetFilter();
38
+ },
39
+ },
40
+ };
41
+ </script>
@@ -0,0 +1,181 @@
1
+ <template>
2
+ <div v-loading="loading" class="generic-table">
3
+ <slot>
4
+ <el-row v-if="showTopFilter" :gutter="20">
5
+ <generic-top-filter ref="genericTopFilter" />
6
+ </el-row>
7
+ <el-row :gutter="20">
8
+ <el-col :span="18">
9
+ <generic-rows />
10
+ <el-row>
11
+ <el-col>
12
+ <generic-paginator />
13
+ </el-col>
14
+ </el-row>
15
+ </el-col>
16
+ <el-col :span="6">
17
+ <generic-filter ref="genericFilter" />
18
+ </el-col>
19
+ </el-row>
20
+ </slot>
21
+ </div>
22
+ </template>
23
+ <script>
24
+ import GenericPaginator from "./GenericPaginator";
25
+ import GenericFilter from "./GenericFilter";
26
+ import GenericTopFilter from "./GenericTopFilter";
27
+ import GenericRows from "./GenericRows";
28
+ import MetaModel from "../../models/meta-model.ts";
29
+ import ListQueryService from "../../services/list-query-service.ts";
30
+ import FilterConverter from "./filter-convertor.ts";
31
+ export default {
32
+ name: "GenericTable",
33
+ components: {
34
+ GenericRows,
35
+ GenericFilter,
36
+ GenericPaginator,
37
+ GenericTopFilter,
38
+ },
39
+ provide() {
40
+ const data = {};
41
+ ["items", "fields", "filters", "loading", "meta"].forEach((key) => {
42
+ Object.defineProperty(data, key, {
43
+ enumerable: true,
44
+ get: () => this[key],
45
+ });
46
+ });
47
+ return {
48
+ data,
49
+ search: this.search,
50
+ actions: {
51
+ handleSizeChange: this.handleSizeChange,
52
+ handleCurrentChange: this.handleCurrentChange,
53
+ handleFilterChange: this.handleFilterChange,
54
+ handleApplyFilter: this.handleApplyFilter,
55
+ handleResetFilter: this.handleResetFilter,
56
+ },
57
+ };
58
+ },
59
+ props: {
60
+ repository: {
61
+ default() {
62
+ return {};
63
+ },
64
+ type: Object,
65
+ },
66
+ title: {
67
+ default: "",
68
+ type: String,
69
+ },
70
+ fields: {
71
+ default: () => [],
72
+ type: Array,
73
+ },
74
+ filters: {
75
+ default: () => [],
76
+ type: Array,
77
+ },
78
+ },
79
+ data: function () {
80
+ let search = {};
81
+ const filterConvertor = new FilterConverter();
82
+ const listQueryService = new ListQueryService(
83
+ this.$route.name,
84
+ this.$services.localStorage()
85
+ );
86
+ for (const column of this.filters) {
87
+ search[column.name] = {
88
+ operator: "",
89
+ value: "",
90
+ position: column.position ? column.position : null,
91
+ };
92
+ }
93
+ search = Object.assign(search, listQueryService.getListQuery().search);
94
+ return {
95
+ loading: false,
96
+ filter: {},
97
+ items: [],
98
+ search: search,
99
+ meta: new MetaModel(),
100
+ filterConvertor: filterConvertor,
101
+ listQueryService: listQueryService,
102
+ };
103
+ },
104
+ computed: {
105
+ showTopFilter() {
106
+ if (this.filters.filter((e) => e.position === "top").length > 0) {
107
+ return true;
108
+ }
109
+ return false;
110
+ },
111
+ queryFilter() {
112
+ const meta = this.listQueryService.getListQuery().meta;
113
+ const query = {
114
+ page: this.meta?.pagination?.current_page
115
+ ? this.meta.pagination.current_page
116
+ : meta.page,
117
+ limit: this.meta?.pagination?.per_page
118
+ ? this.meta.pagination.per_page
119
+ : meta.limit,
120
+ };
121
+ return { ...query, ...this.filter };
122
+ },
123
+ },
124
+ mounted() {
125
+ this.filter = this.$refs.genericFilter.getFilter();
126
+ this.fetch();
127
+ },
128
+ methods: {
129
+ async fetch() {
130
+ this.loading = true;
131
+ try {
132
+ const response = await this.repository.all(this.queryFilter);
133
+ this.items = response.data;
134
+ this.meta = response.meta;
135
+ } catch (e) {
136
+ this.$message.error(e.message);
137
+ }
138
+ this.loading = false;
139
+ },
140
+
141
+ handleSizeChange(val) {
142
+ this.listQueryService.updateListQuery({ meta: { limit: val } });
143
+ this.meta.pagination.per_page = val;
144
+ this.fetch();
145
+ },
146
+ handleCurrentChange(val) {
147
+ this.listQueryService.updateListQuery({ meta: { page: val } });
148
+ this.meta.pagination.current_page = val;
149
+ this.fetch();
150
+ },
151
+ handleFilterChange(val) {
152
+ this.filter = val;
153
+ this.meta.pagination.current_page = 1;
154
+ this.fetch();
155
+ },
156
+ handleApplyFilter() {
157
+ this.listQueryService.updateListQuery({ search: this.search });
158
+ this.handleFilterChange(this.filterConvertor.applyFilter(this.search));
159
+ },
160
+ handleResetFilter() {
161
+ console.log(this.search);
162
+ for (const column in this.search) {
163
+ if (this.search[column].position === "top") {
164
+ this.search[column] = Object.assign(this.search[column], {
165
+ value: "",
166
+ });
167
+ } else {
168
+ this.search[column] = Object.assign(this.search[column], {
169
+ operator: "",
170
+ value: "",
171
+ });
172
+ }
173
+ }
174
+ this.listQueryService.updateListQuery({ search: this.search });
175
+ this.handleFilterChange({});
176
+ },
177
+ },
178
+ };
179
+ </script>
180
+
181
+ <style scoped></style>