pui9-dashboard 1.16.4
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/README.md +20 -0
- package/dist/demo.html +10 -0
- package/dist/pui9-dashboard.common.js +143549 -0
- package/dist/pui9-dashboard.common.js.map +1 -0
- package/dist/pui9-dashboard.css +5 -0
- package/dist/pui9-dashboard.umd.js +143559 -0
- package/dist/pui9-dashboard.umd.js.map +1 -0
- package/dist/pui9-dashboard.umd.min.js +28 -0
- package/dist/pui9-dashboard.umd.min.js.map +1 -0
- package/package-lock.json +16026 -0
- package/package.json +70 -0
- package/src/components/PuiDashboard.vue +87 -0
- package/src/components/PuiDashboardOverview.vue +12 -0
- package/src/components/PuiGridLayout.vue +127 -0
- package/src/components/PuiWidgetOverview.vue +41 -0
- package/src/components/puidashboard/PuiDashboardForm.vue +143 -0
- package/src/components/puidashboard/PuiDashboardGrid.vue +14 -0
- package/src/components/puiwidget/PuiWidgetForm.vue +129 -0
- package/src/components/puiwidget/PuiWidgetGrid.vue +14 -0
- package/src/index.js +17 -0
- package/src/widgets/PuiWidgetDatatable.vue +155 -0
- package/src/widgets/PuiWidgetDatatableOptions.js +13 -0
- package/src/widgets/PuiWidgetEChart.vue +188 -0
- package/src/widgets/PuiWidgetEChartOptions.js +79 -0
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pui9-dashboard",
|
|
3
|
+
"description": "PUI9 Dashboard Components",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "Prodevelop S.L."
|
|
6
|
+
},
|
|
7
|
+
"version": "1.16.4",
|
|
8
|
+
"license": "Copyright",
|
|
9
|
+
"main": "dist/pui9-dashboard.common.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"serve": "vue-cli-service serve",
|
|
12
|
+
"build-bundle": "vue-cli-service build --target lib --name pui9-dashboard ./src/index.js",
|
|
13
|
+
"prepare": "npm run build-bundle",
|
|
14
|
+
"lint": "vue-cli-service lint"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"echarts": "5.1.2",
|
|
18
|
+
"vue-grid-layout": "2.3.12"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@vue/cli-plugin-babel": "4.5.13",
|
|
22
|
+
"@vue/cli-plugin-eslint": "4.5.13",
|
|
23
|
+
"@vue/cli-service": "4.5.13",
|
|
24
|
+
"autoprefixer": "9.8.6",
|
|
25
|
+
"babel-eslint": "10.1.0",
|
|
26
|
+
"core-js": "3.17.2",
|
|
27
|
+
"css-loader": "0.28.11",
|
|
28
|
+
"deepmerge": "4.2.2",
|
|
29
|
+
"eslint": "6.8.0",
|
|
30
|
+
"eslint-plugin-vue": "6.2.2",
|
|
31
|
+
"postcss-css-variables": "0.18.0",
|
|
32
|
+
"postcss-import": "12.0.1",
|
|
33
|
+
"postcss-loader": "4.1.0",
|
|
34
|
+
"postcss-nested": "4.2.3",
|
|
35
|
+
"postcss-url": "8.0.0",
|
|
36
|
+
"sass": "1.27.0",
|
|
37
|
+
"sass-loader": "10.0.2",
|
|
38
|
+
"stylus": "0.54.8",
|
|
39
|
+
"stylus-loader": "3.0.2",
|
|
40
|
+
"vue": "2.6.14",
|
|
41
|
+
"vue-i18n": "8.25.0",
|
|
42
|
+
"vue-cli-plugin-vuetify": "2.4.1",
|
|
43
|
+
"vue-template-compiler": "2.6.14",
|
|
44
|
+
"vuetify-loader": "1.7.3",
|
|
45
|
+
"vuetify": "2.3.23"
|
|
46
|
+
},
|
|
47
|
+
"eslintConfig": {
|
|
48
|
+
"root": true,
|
|
49
|
+
"env": {
|
|
50
|
+
"node": true
|
|
51
|
+
},
|
|
52
|
+
"extends": [
|
|
53
|
+
"plugin:vue/essential",
|
|
54
|
+
"eslint:recommended"
|
|
55
|
+
],
|
|
56
|
+
"parserOptions": {
|
|
57
|
+
"parser": "babel-eslint"
|
|
58
|
+
},
|
|
59
|
+
"rules": {}
|
|
60
|
+
},
|
|
61
|
+
"browserslist": [
|
|
62
|
+
"> 1%",
|
|
63
|
+
"last 2 versions"
|
|
64
|
+
],
|
|
65
|
+
"files": [
|
|
66
|
+
"dist/*",
|
|
67
|
+
"src/*",
|
|
68
|
+
"*.json"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ml-4 mr-4 overflow-y-auto" :style="{ 'max-height': maxHeight }">
|
|
3
|
+
<v-select
|
|
4
|
+
v-if="!defaultDashboard"
|
|
5
|
+
v-model="dashboardSelected"
|
|
6
|
+
:items="dashboards"
|
|
7
|
+
:item-text="(item) => `${item.name}`"
|
|
8
|
+
return-object
|
|
9
|
+
placeholder=" "
|
|
10
|
+
outlined
|
|
11
|
+
solo
|
|
12
|
+
hide-details
|
|
13
|
+
></v-select>
|
|
14
|
+
<pui-grid-layout :key="layoutKey" :layout="layout" :widgets="widgets" :draggable="false" :resizable="false" />
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
import PuiGridLayout from './PuiGridLayout.vue';
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
name: 'PuiDashboard',
|
|
23
|
+
components: { PuiGridLayout },
|
|
24
|
+
props: {
|
|
25
|
+
defaultDashboard: {
|
|
26
|
+
type: Object,
|
|
27
|
+
required: false,
|
|
28
|
+
default: null
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
data() {
|
|
32
|
+
return {
|
|
33
|
+
dashboardSelected: null,
|
|
34
|
+
dashboards: [],
|
|
35
|
+
widgets: [],
|
|
36
|
+
layoutKey: 1
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
computed: {
|
|
40
|
+
maxHeight() {
|
|
41
|
+
if (this.$store.state.global.appContainerHeader) {
|
|
42
|
+
return `${window.innerHeight - 78}px`;
|
|
43
|
+
}
|
|
44
|
+
return `${window.innerHeight}px`;
|
|
45
|
+
},
|
|
46
|
+
layout() {
|
|
47
|
+
if (this.defaultDashboard && this.defaultDashboard.definition) {
|
|
48
|
+
return this.defaultDashboard.definition;
|
|
49
|
+
}
|
|
50
|
+
return (this.dashboardSelected && this.dashboardSelected.definition) || [];
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
watch: {
|
|
54
|
+
dashboardSelected() {
|
|
55
|
+
// force redraw pui-grid-layout component on dashboard selected
|
|
56
|
+
this.layoutKey += 1;
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
mounted() {
|
|
60
|
+
this.$puiRequests.postRequest('/puisearch', { model: 'puidashboard', rows: 100 }, (response) => {
|
|
61
|
+
if (response && response.data && response.data.data) {
|
|
62
|
+
this.dashboards = response.data.data.map((item) => {
|
|
63
|
+
return {
|
|
64
|
+
id: item.id,
|
|
65
|
+
name: item.name,
|
|
66
|
+
definition: JSON.parse(item.definition)
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
this.dashboardSelected = this.dashboards[0];
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
this.$puiRequests.postRequest('/puisearch', { model: 'puiwidget', rows: 100 }, (response) => {
|
|
73
|
+
if (response && response.data && response.data.data) {
|
|
74
|
+
this.widgets = response.data.data.map((item) => {
|
|
75
|
+
return {
|
|
76
|
+
id: item.id,
|
|
77
|
+
name: item.name,
|
|
78
|
+
component: item.component,
|
|
79
|
+
type: item.type,
|
|
80
|
+
definition: JSON.parse(item.definition)
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
</script>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<grid-layout
|
|
3
|
+
:layout.sync="internalLayout"
|
|
4
|
+
:row-height="30"
|
|
5
|
+
:is-draggable="draggable"
|
|
6
|
+
:is-resizable="resizable"
|
|
7
|
+
:responsive="responsive"
|
|
8
|
+
:vertical-compact="true"
|
|
9
|
+
:use-css-transforms="true"
|
|
10
|
+
@layout-ready="layoutReadyEvent"
|
|
11
|
+
>
|
|
12
|
+
<grid-item v-for="item in internalLayout" :x="item.x" :y="item.y" :w="item.w" :h="item.h" :i="item.i" :key="item.i" @resize="resizeEvent">
|
|
13
|
+
<component
|
|
14
|
+
:is="getWidgetProperty(item.widget, 'component')"
|
|
15
|
+
:type="getWidgetProperty(item.widget, 'type')"
|
|
16
|
+
:definition="getWidgetProperty(item.widget, 'definition')"
|
|
17
|
+
:resized="item.resized"
|
|
18
|
+
/>
|
|
19
|
+
<span class="remove" v-if="draggable && resizable" @click="removeItem(item.i)">x</span>
|
|
20
|
+
</grid-item>
|
|
21
|
+
</grid-layout>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
import { GridLayout, GridItem } from 'vue-grid-layout';
|
|
26
|
+
|
|
27
|
+
export default {
|
|
28
|
+
components: { GridLayout, GridItem },
|
|
29
|
+
props: {
|
|
30
|
+
layout: {
|
|
31
|
+
type: Array,
|
|
32
|
+
required: true
|
|
33
|
+
},
|
|
34
|
+
widgets: {
|
|
35
|
+
type: Array,
|
|
36
|
+
required: true
|
|
37
|
+
},
|
|
38
|
+
draggable: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: true
|
|
41
|
+
},
|
|
42
|
+
resizable: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: true
|
|
45
|
+
},
|
|
46
|
+
responsive: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
computed: {
|
|
52
|
+
internalLayout: {
|
|
53
|
+
// getter
|
|
54
|
+
get() {
|
|
55
|
+
return [...this.layout];
|
|
56
|
+
},
|
|
57
|
+
// setter
|
|
58
|
+
set() {
|
|
59
|
+
// not remove to prevent vue warning
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
methods: {
|
|
64
|
+
layoutReadyEvent() {
|
|
65
|
+
for (let j = 0; j < this.internalLayout.length; j++) {
|
|
66
|
+
const item = this.internalLayout[j];
|
|
67
|
+
item.resized = { width: item.resized.width, height: item.resized.height };
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
resizeEvent(i, newH, newW, newHPx, newWPx) {
|
|
71
|
+
for (let j = 0; j < this.internalLayout.length; j++) {
|
|
72
|
+
const item = this.internalLayout[j];
|
|
73
|
+
if (item.i === i) {
|
|
74
|
+
item.resized = { width: newWPx, height: newHPx };
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
getWidgetProperty(widgetId, property) {
|
|
80
|
+
for (let i = 0; i < this.widgets.length; i++) {
|
|
81
|
+
const widget = this.widgets[i];
|
|
82
|
+
if (widget.id === widgetId) {
|
|
83
|
+
return widget[property];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
},
|
|
88
|
+
removeItem(index) {
|
|
89
|
+
this.$emit('remove-widget', index);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<style lang="postcss">
|
|
96
|
+
.vue-grid-layout {
|
|
97
|
+
background: #eee;
|
|
98
|
+
}
|
|
99
|
+
.vue-grid-item .resizing {
|
|
100
|
+
opacity: 0.9;
|
|
101
|
+
}
|
|
102
|
+
.vue-grid-item .no-drag {
|
|
103
|
+
height: 100%;
|
|
104
|
+
width: 100%;
|
|
105
|
+
}
|
|
106
|
+
.vue-draggable-handle {
|
|
107
|
+
position: absolute;
|
|
108
|
+
width: 20px;
|
|
109
|
+
height: 20px;
|
|
110
|
+
top: 0;
|
|
111
|
+
left: 0;
|
|
112
|
+
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><circle cx='5' cy='5' r='5' fill='#999999'/></svg>")
|
|
113
|
+
no-repeat;
|
|
114
|
+
background-position: bottom right;
|
|
115
|
+
padding: 0 8px 8px 0;
|
|
116
|
+
background-repeat: no-repeat;
|
|
117
|
+
background-origin: content-box;
|
|
118
|
+
box-sizing: border-box;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
}
|
|
121
|
+
.remove {
|
|
122
|
+
position: absolute;
|
|
123
|
+
right: 2px;
|
|
124
|
+
top: 0;
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="overflow-y-auto" :style="{ 'max-height': maxHeight }">
|
|
3
|
+
<v-row dense class="ma-3">
|
|
4
|
+
<v-col cols="12" sm="3" md="6" v-for="(item, index) in items" :key="index" style="max-height: 500px">
|
|
5
|
+
<component :is="item.component" :type="item.type" :definition="item.definition" :resized="{ height: 450 }" />
|
|
6
|
+
</v-col>
|
|
7
|
+
</v-row>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
export default {
|
|
13
|
+
name: 'PuiWidgetOverview',
|
|
14
|
+
data() {
|
|
15
|
+
return {
|
|
16
|
+
items: []
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
computed: {
|
|
20
|
+
maxHeight() {
|
|
21
|
+
if (this.$store.state.global.appContainerHeader) {
|
|
22
|
+
return `${window.innerHeight - 134}px`;
|
|
23
|
+
}
|
|
24
|
+
return `${window.innerHeight - 78}px`;
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
mounted() {
|
|
28
|
+
this.$puiRequests.postRequest('/puisearch', { model: 'puiwidget', rows: 100 }, (response) => {
|
|
29
|
+
if (response && response.data && response.data.data) {
|
|
30
|
+
this.items = response.data.data.map(function (item) {
|
|
31
|
+
return {
|
|
32
|
+
component: item.component,
|
|
33
|
+
type: item.type,
|
|
34
|
+
definition: JSON.parse(item.definition)
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
</script>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="pui-form">
|
|
3
|
+
<v-form class="mb-4 pb-4" ref="form" v-model="valid" lazy-validation v-if="modelLoaded">
|
|
4
|
+
<v-row class="pui-form-layout">
|
|
5
|
+
<v-col cols="12">
|
|
6
|
+
<pui-field-set :title="$t('form.puidashboard')">
|
|
7
|
+
<v-row dense>
|
|
8
|
+
<v-col cols="6">
|
|
9
|
+
<pui-text-field
|
|
10
|
+
:label="$t('form.puidashboard.name')"
|
|
11
|
+
v-model="model.name"
|
|
12
|
+
:disabled="formDisabled"
|
|
13
|
+
maxlength="100"
|
|
14
|
+
toplabel
|
|
15
|
+
required
|
|
16
|
+
></pui-text-field>
|
|
17
|
+
</v-col>
|
|
18
|
+
<v-col cols="6">
|
|
19
|
+
<v-btn @click="dialog = true">Add widget</v-btn>
|
|
20
|
+
</v-col>
|
|
21
|
+
</v-row>
|
|
22
|
+
<v-row dense>
|
|
23
|
+
<v-col cols="12">
|
|
24
|
+
<pui-grid-layout :layout="layout" :widgets="widgets" @remove-widget="removeWidget" />
|
|
25
|
+
</v-col>
|
|
26
|
+
</v-row>
|
|
27
|
+
</pui-field-set>
|
|
28
|
+
</v-col>
|
|
29
|
+
</v-row>
|
|
30
|
+
<pui-form-footer>
|
|
31
|
+
<pui-form-footer-btns :formDisabled="formDisabled" :saveDisabled="saving" :save="save" :back="back"></pui-form-footer-btns>
|
|
32
|
+
</pui-form-footer>
|
|
33
|
+
</v-form>
|
|
34
|
+
<pui-form-loading v-else></pui-form-loading>
|
|
35
|
+
|
|
36
|
+
<v-dialog v-model="dialog" max-width="450">
|
|
37
|
+
<v-card>
|
|
38
|
+
<v-card-title>Select widget</v-card-title>
|
|
39
|
+
|
|
40
|
+
<v-card-text>
|
|
41
|
+
<v-select
|
|
42
|
+
v-model="widgetSelected"
|
|
43
|
+
:items="widgets"
|
|
44
|
+
:item-text="(item) => `${item.name} (${item.type})`"
|
|
45
|
+
return-object
|
|
46
|
+
placeholder=" "
|
|
47
|
+
outlined
|
|
48
|
+
solo
|
|
49
|
+
hide-details
|
|
50
|
+
></v-select>
|
|
51
|
+
</v-card-text>
|
|
52
|
+
|
|
53
|
+
<v-card-actions>
|
|
54
|
+
<v-spacer></v-spacer>
|
|
55
|
+
|
|
56
|
+
<v-btn text @click="dialog = false">{{ $t('form.close') }}</v-btn>
|
|
57
|
+
|
|
58
|
+
<v-btn
|
|
59
|
+
color="green darken-1"
|
|
60
|
+
text
|
|
61
|
+
@click="
|
|
62
|
+
addWidget(widgetSelected);
|
|
63
|
+
dialog = false;
|
|
64
|
+
"
|
|
65
|
+
>{{ $t('form.ok') }}</v-btn
|
|
66
|
+
>
|
|
67
|
+
</v-card-actions>
|
|
68
|
+
</v-card>
|
|
69
|
+
</v-dialog>
|
|
70
|
+
</div>
|
|
71
|
+
</template>
|
|
72
|
+
|
|
73
|
+
<script>
|
|
74
|
+
import PuiFormMethodsMixin from '../../../../pui9-mixins/PuiFormMethodsMixin';
|
|
75
|
+
import PuiGridLayout from '../PuiGridLayout.vue';
|
|
76
|
+
|
|
77
|
+
export default {
|
|
78
|
+
name: 'PuiDashboardForm',
|
|
79
|
+
mixins: [PuiFormMethodsMixin],
|
|
80
|
+
components: { PuiGridLayout },
|
|
81
|
+
data() {
|
|
82
|
+
return {
|
|
83
|
+
modelName: 'puidashboard',
|
|
84
|
+
dialog: false,
|
|
85
|
+
index: 0,
|
|
86
|
+
layout: [],
|
|
87
|
+
widgets: [],
|
|
88
|
+
widgetSelected: null
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
mounted() {
|
|
92
|
+
this.$puiRequests.postRequest('/puisearch', { model: 'puiwidget', rows: 100 }, (response) => {
|
|
93
|
+
if (response && response.data && response.data.data) {
|
|
94
|
+
this.widgets = response.data.data.map((item) => {
|
|
95
|
+
return {
|
|
96
|
+
id: item.id,
|
|
97
|
+
name: item.name,
|
|
98
|
+
component: item.component,
|
|
99
|
+
type: item.type,
|
|
100
|
+
definition: JSON.parse(item.definition)
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
methods: {
|
|
107
|
+
addWidget(widget) {
|
|
108
|
+
// Add a new item. It must have a unique key!
|
|
109
|
+
this.layout.push({
|
|
110
|
+
x: (this.layout.length * 2) % (this.colNum || 12),
|
|
111
|
+
y: this.layout.length + (this.colNum || 12), // puts it at the bottom
|
|
112
|
+
w: 6,
|
|
113
|
+
h: 6,
|
|
114
|
+
i: this.index,
|
|
115
|
+
widget: widget.id
|
|
116
|
+
});
|
|
117
|
+
// Increment the counter to ensure key is always unique.
|
|
118
|
+
this.index++;
|
|
119
|
+
// Reset last widget selected
|
|
120
|
+
this.widgetSelected = null;
|
|
121
|
+
},
|
|
122
|
+
removeWidget(widget) {
|
|
123
|
+
const index = this.layout.map((item) => item.i).indexOf(widget);
|
|
124
|
+
this.layout.splice(index, 1);
|
|
125
|
+
},
|
|
126
|
+
afterGetData() {
|
|
127
|
+
if (this.model.definition) {
|
|
128
|
+
this.layout = JSON.parse(this.model.definition);
|
|
129
|
+
this.index =
|
|
130
|
+
Math.max.apply(
|
|
131
|
+
Math,
|
|
132
|
+
this.layout.map(function (item) {
|
|
133
|
+
return item.i;
|
|
134
|
+
})
|
|
135
|
+
) + 1;
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
beforeSave() {
|
|
139
|
+
this.model.definition = JSON.stringify(this.layout);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
</script>
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="pui-form">
|
|
3
|
+
<v-form class="mb-4 pb-4" ref="form" v-model="valid" lazy-validation v-if="modelLoaded">
|
|
4
|
+
<v-row class="pui-form-layout">
|
|
5
|
+
<v-col cols="5">
|
|
6
|
+
<pui-field-set highlighted>
|
|
7
|
+
<v-row dense>
|
|
8
|
+
<v-col cols="12">
|
|
9
|
+
<pui-text-field
|
|
10
|
+
:label="$t('form.puiwidget.name')"
|
|
11
|
+
v-model="model.name"
|
|
12
|
+
:disabled="formDisabled"
|
|
13
|
+
maxlength="100"
|
|
14
|
+
toplabel
|
|
15
|
+
required
|
|
16
|
+
></pui-text-field>
|
|
17
|
+
</v-col>
|
|
18
|
+
<v-col cols="12">
|
|
19
|
+
<pui-select
|
|
20
|
+
:id="`type-${modelName}`"
|
|
21
|
+
:attach="`type-${modelName}`"
|
|
22
|
+
:label="this.$t('form.puiwidget.type')"
|
|
23
|
+
toplabel
|
|
24
|
+
required
|
|
25
|
+
:disabled="formDisabled"
|
|
26
|
+
v-model="model"
|
|
27
|
+
modelName="puiwidgettype"
|
|
28
|
+
:modelFormMapping="{ id: 'typeid' }"
|
|
29
|
+
:itemsToSelect="[{ id: model.typeid }]"
|
|
30
|
+
itemValue="id"
|
|
31
|
+
itemText="name"
|
|
32
|
+
></pui-select>
|
|
33
|
+
</v-col>
|
|
34
|
+
<v-col cols="12">
|
|
35
|
+
<component :is="component" :type="componentType" :key="componentKey" :resized="{ height: 450 }" />
|
|
36
|
+
</v-col>
|
|
37
|
+
</v-row>
|
|
38
|
+
</pui-field-set>
|
|
39
|
+
</v-col>
|
|
40
|
+
<v-col cols="7">
|
|
41
|
+
<pui-field-set :title="$t('form.puiwidget.definition.attributes')">
|
|
42
|
+
<v-row dense>
|
|
43
|
+
<v-col cols="12" v-for="(field, index) in definitionModel" :key="index">
|
|
44
|
+
<component
|
|
45
|
+
v-if="field.component === 'pui-select'"
|
|
46
|
+
:is="field.component"
|
|
47
|
+
toplabel
|
|
48
|
+
:label="$t(field.label)"
|
|
49
|
+
v-model="field.value"
|
|
50
|
+
:items="field.items"
|
|
51
|
+
:itemsToSelect="field.value ? [field.value] : []"
|
|
52
|
+
:itemText="
|
|
53
|
+
(item) => {
|
|
54
|
+
return item;
|
|
55
|
+
}
|
|
56
|
+
"
|
|
57
|
+
:required="field.required"
|
|
58
|
+
/>
|
|
59
|
+
<component
|
|
60
|
+
v-else
|
|
61
|
+
:is="field.component"
|
|
62
|
+
toplabel
|
|
63
|
+
:label="$t(field.label)"
|
|
64
|
+
v-model="field.value"
|
|
65
|
+
:required="field.required"
|
|
66
|
+
/>
|
|
67
|
+
</v-col>
|
|
68
|
+
<v-col cols="12">
|
|
69
|
+
<pui-text-area toplabel v-model="model.definition" maxlength="1000" disabled noeditable />
|
|
70
|
+
</v-col>
|
|
71
|
+
</v-row>
|
|
72
|
+
</pui-field-set>
|
|
73
|
+
</v-col>
|
|
74
|
+
</v-row>
|
|
75
|
+
<pui-form-footer>
|
|
76
|
+
<pui-form-footer-btns :formDisabled="formDisabled" :saveDisabled="saving" :save="save" :back="back"></pui-form-footer-btns>
|
|
77
|
+
</pui-form-footer>
|
|
78
|
+
</v-form>
|
|
79
|
+
<pui-form-loading v-else></pui-form-loading>
|
|
80
|
+
</div>
|
|
81
|
+
</template>
|
|
82
|
+
|
|
83
|
+
<script>
|
|
84
|
+
import PuiFormMethodsMixin from '../../../../pui9-mixins/PuiFormMethodsMixin';
|
|
85
|
+
|
|
86
|
+
export default {
|
|
87
|
+
name: 'PuiWidgetForm',
|
|
88
|
+
mixins: [PuiFormMethodsMixin],
|
|
89
|
+
data() {
|
|
90
|
+
return {
|
|
91
|
+
modelName: 'puiwidget',
|
|
92
|
+
component: null,
|
|
93
|
+
componentType: null,
|
|
94
|
+
componentKey: 1,
|
|
95
|
+
definitionModel: null
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
watch: {
|
|
99
|
+
definitionModel: {
|
|
100
|
+
handler(newVal) {
|
|
101
|
+
this.model.definition = JSON.stringify(newVal);
|
|
102
|
+
},
|
|
103
|
+
deep: true
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
mounted() {
|
|
107
|
+
this.$puiEvents.$on(`onPuiSelect_selectedItems-type-${this.modelName}`, (newVal) => {
|
|
108
|
+
this.component = newVal.model.component;
|
|
109
|
+
this.componentType = newVal.model.type;
|
|
110
|
+
this.componentKey = this.componentKey + 1;
|
|
111
|
+
|
|
112
|
+
if (this.isCreatingElement || this.model.typeid !== this.initialTypeid) {
|
|
113
|
+
this.model.definition = newVal.model.definition;
|
|
114
|
+
}
|
|
115
|
+
this.definitionModel = JSON.parse(this.model.definition);
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
beforeDestroy() {
|
|
119
|
+
this.$puiEvents.$off(`onPuiSelect_selectedItems-type-${this.modelName}`);
|
|
120
|
+
},
|
|
121
|
+
methods: {
|
|
122
|
+
afterGetData() {
|
|
123
|
+
if (!this.isCreatingElement) {
|
|
124
|
+
this.initialTypeid = this.model.typeid;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
</script>
|
package/src/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import PuiDashboard from './components/PuiDashboard';
|
|
2
|
+
import PuiWidgetDatatable from './widgets/PuiWidgetDatatable';
|
|
3
|
+
import PuiWidgetEChart from './widgets/PuiWidgetEChart';
|
|
4
|
+
|
|
5
|
+
const Components = {
|
|
6
|
+
PuiDashboard,
|
|
7
|
+
PuiWidgetDatatable,
|
|
8
|
+
PuiWidgetEChart
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
install(Vue) {
|
|
13
|
+
Object.keys(Components).forEach((name) => {
|
|
14
|
+
Vue.component(name, Components[name]);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
};
|