Support to dynamic dashboard (#219)
* First test for dynamic load * add support to list dashboard items * change some dashboards names Co-authored-by: Yamel Senih <ysenih@erpya.com>pull/3759/head
parent
d622eec48b
commit
f0630d79d6
|
@ -347,6 +347,10 @@ export function requestPrintFormats({ tableName, reportViewUuid, processUuid })
|
|||
return Instance.call(this).requestPrintFormats({ tableName: tableName, reportViewUuid: reportViewUuid, processUuid: processUuid })
|
||||
}
|
||||
|
||||
export function requestLisDashboards(roleUuid) {
|
||||
return Instance.call(this).requestDashboards(roleUuid)
|
||||
}
|
||||
|
||||
export function requestLanguages() {
|
||||
return Instance.call(this).requestLanguages()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<component
|
||||
:is="renderDashboard"
|
||||
:ref="dashboard.dashboardName"
|
||||
:metadata="dashboard"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
props: {
|
||||
metadata: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dashboard: this.metadata
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// load the component that is indicated in the attributes of received property
|
||||
renderDashboard() {
|
||||
if (this.metadata.fileName === 'userfavorites') {
|
||||
return () => import('@/components/ADempiere/Dashboard/favourites')
|
||||
}
|
||||
return () => import(`@/components/ADempiere/Dashboard/${this.metadata.fileName}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dashboard-editor-container {
|
||||
padding: 32px;
|
||||
background-color: rgb(240, 242, 245);
|
||||
position: relative;
|
||||
|
||||
.github-corner {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
border: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.chart-wrapper {
|
||||
background: #fff;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<el-collapse v-model="activeRecentItems" accordion>
|
||||
<el-collapse-item name="recentItems">
|
||||
<template slot="title">
|
||||
<i class="el-icon-time" style="margin-right: 4px;margin-left: 10px;" /> {{ $t('profile.recentItems') }}
|
||||
</template>
|
||||
<el-card class="box-card" :body-style="{ padding: '0px' }" shadow="never">
|
||||
<div class="recent-items">
|
||||
<el-table :data="search.length ? filterResult(search) : recentItems" max-height="455" @row-click="handleClick">
|
||||
<el-table-column width="40">
|
||||
<template slot-scope="{row}">
|
||||
<svg-icon :icon-class="row.icon" class="icon-window" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column>
|
||||
<template slot="header" slot-scope="scope" class="clearfix">
|
||||
<el-input
|
||||
v-model="search"
|
||||
size="mini"
|
||||
:metadata="scope"
|
||||
:placeholder="$t('table.dataTable.search')"
|
||||
/>
|
||||
</template>
|
||||
<template slot-scope="{row}">
|
||||
<span>{{ row.displayName }}</span>
|
||||
<el-tag class="action-tag">{{ $t(`views.${row.action}`) }}</el-tag>
|
||||
<br>
|
||||
<span class="time">{{ translateDate(row.updated) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getRecentItems as getRecentItemsFromServer } from '@/api/ADempiere'
|
||||
import { convertAction } from '@/utils/ADempiere/dictionaryUtils'
|
||||
export default {
|
||||
name: 'RecentItems',
|
||||
data() {
|
||||
return {
|
||||
activeRecentItems: 'recentItems',
|
||||
recentItems: [],
|
||||
isLoaded: true,
|
||||
search: '',
|
||||
accentRegexp: /[\u0300-\u036f]/g
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getterRecentItems() {
|
||||
return this.$store.getters.getRecentItems
|
||||
},
|
||||
cachedViews() {
|
||||
return this.$store.getters.cachedViews
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getRecentItems()
|
||||
this.subscribeChanges()
|
||||
},
|
||||
methods: {
|
||||
checkOpened(uuid) {
|
||||
return this.cachedViews.includes(uuid)
|
||||
},
|
||||
getRecentItems() {
|
||||
return new Promise((resolve, reject) => {
|
||||
getRecentItemsFromServer()
|
||||
.then(response => {
|
||||
const recentItems = response.getRecentitemsList().map(item => {
|
||||
const actionConverted = convertAction(item.getAction())
|
||||
return {
|
||||
action: actionConverted.name,
|
||||
icon: actionConverted.icon,
|
||||
displayName: item.getDisplayname(),
|
||||
menuUuid: item.getMenuuuid(),
|
||||
menuName: item.getMenuname(),
|
||||
windowUuid: item.getWindowuuid(),
|
||||
tableId: item.getTableid(),
|
||||
recordId: item.getRecordid(),
|
||||
uuidRecord: item.getRecorduuid(),
|
||||
tabUuid: item.getTabuuid(),
|
||||
updated: new Date(item.getUpdated()),
|
||||
description: item.getMenudescription()
|
||||
}
|
||||
})
|
||||
this.recentItems = recentItems
|
||||
this.isLoaded = false
|
||||
resolve(recentItems)
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
handleClick(row) {
|
||||
if (!this.isEmptyValue(row.uuidRecord)) {
|
||||
this.$router.push({ name: row.menuUuid, query: { action: row.uuidRecord, tabParent: 0 }})
|
||||
} else {
|
||||
this.$router.push({ name: row.menuUuid })
|
||||
}
|
||||
},
|
||||
subscribeChanges() {
|
||||
this.$store.subscribe((mutation, state) => {
|
||||
if (mutation.type === 'notifyDashboardRefresh') {
|
||||
this.getRecentItems()
|
||||
}
|
||||
})
|
||||
},
|
||||
filterResult(search) {
|
||||
return this.recentItems.filter(item => this.ignoreAccent(item.displayName).toLowerCase().includes(this.ignoreAccent(search.toLowerCase())))
|
||||
},
|
||||
ignoreAccent(s) {
|
||||
if (!s) { return '' }
|
||||
return s.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
|
||||
},
|
||||
translateDate(value) {
|
||||
return this.$d(new Date(value), 'long', this.language)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.search_recent {
|
||||
width: 50%!important;
|
||||
float: right;
|
||||
}
|
||||
.header {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.recent-items {
|
||||
height: 455px;
|
||||
overflow: auto;
|
||||
}
|
||||
.time {
|
||||
float: left;
|
||||
font-size: 11px;
|
||||
color: #999;
|
||||
}
|
||||
.card-box {
|
||||
cursor: pointer;
|
||||
}
|
||||
.card-content {
|
||||
font-size: 15px;
|
||||
}
|
||||
.icon-window {
|
||||
font-size: x-large;
|
||||
color: #36a3f7;
|
||||
}
|
||||
.action-tag {
|
||||
float: right;
|
||||
}
|
||||
</style>
|
|
@ -1,4 +1,5 @@
|
|||
// Default store for handle dashboard refresh and other functionalities
|
||||
import { requestLisDashboards } from '@/api/ADempiere/data'
|
||||
const dashboard = {
|
||||
state: {
|
||||
dashboard: []
|
||||
|
@ -14,6 +15,39 @@ const dashboard = {
|
|||
actions: {
|
||||
refreshDashboard({ commit, getters }, parameters) {
|
||||
commit('notifyDashboardRefresh', parameters)
|
||||
},
|
||||
listDashboard({ commit }, roleUuid) {
|
||||
return new Promise((resolve, reject) => {
|
||||
requestLisDashboards(roleUuid)
|
||||
.then(response => {
|
||||
const dashboards = response.getDashboardsList().map(item => {
|
||||
return {
|
||||
windowUuid: item.getWindowuuid(),
|
||||
browserUuid: item.getBrowseruuid(),
|
||||
dashboardName: item.getDashboardname(),
|
||||
dashboardDescription: item.getDashboarddescription(),
|
||||
dashboardHtml: item.getDashboardhtml(),
|
||||
columnNo: item.getColumnno(),
|
||||
lineNo: item.getLineno(),
|
||||
isCollapsible: item.getIscollapsible(),
|
||||
isOpenByDefault: item.getIsopenbydefault(),
|
||||
isEventRequired: item.getIseventrequired(),
|
||||
fileName: item.getFilename()
|
||||
}
|
||||
})
|
||||
const roleDashboards = {
|
||||
roleUuid: roleUuid,
|
||||
recordCount: response.getRecordcount(),
|
||||
dashboardList: dashboards,
|
||||
nextPageToken: response.getNextPageToken()
|
||||
}
|
||||
commit('addDashboard', roleDashboards)
|
||||
resolve(roleDashboards)
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
|
@ -21,6 +55,11 @@ const dashboard = {
|
|||
return state.dashboard.find(
|
||||
item => item.uuid === dashboardUuid
|
||||
)
|
||||
},
|
||||
getDashboardByRole: (state) => (roleUuid) => {
|
||||
return state.dashboard.find(
|
||||
item => item.roleUuid === roleUuid
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,108 +1,48 @@
|
|||
<template>
|
||||
<div class="dashboard-editor-container">
|
||||
<github-corner class="github-corner" />
|
||||
|
||||
<panel-group @handleSetLineChartData="handleSetLineChartData" />
|
||||
|
||||
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
|
||||
<line-chart :chart-data="lineChartData" />
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="32">
|
||||
<el-col :xs="24" :sm="24" :lg="8">
|
||||
<div class="chart-wrapper">
|
||||
<raddar-chart />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :lg="8">
|
||||
<div class="chart-wrapper">
|
||||
<pie-chart />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :lg="8">
|
||||
<div class="chart-wrapper">
|
||||
<bar-chart />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="8">
|
||||
<el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;">
|
||||
<recent-items />
|
||||
</el-col>
|
||||
<el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;">
|
||||
<favorites />
|
||||
</el-col>
|
||||
<el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;">
|
||||
<todo-list />
|
||||
</el-col>
|
||||
<el-col :xs="{span: 24}" :sm="{span: 12}" :md="{span: 12}" :lg="{span: 6}" :xl="{span: 6}" style="margin-bottom:30px;">
|
||||
<box-card />
|
||||
</el-col>
|
||||
<el-col :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;">
|
||||
<pending-documents />
|
||||
</el-col>
|
||||
<template v-for="(dashboard, index) in dashboardList">
|
||||
<el-col :key="index" :xs="{span: 24}" :sm="{span: 24}" :md="{span: 24}" :lg="{span: 12}" :xl="{span: 12}" style="padding-right:8px;margin-bottom:30px;">
|
||||
<dashboard :metadata="dashboard" />
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GithubCorner from '@/components/GithubCorner'
|
||||
import PanelGroup from './components/PanelGroup'
|
||||
import LineChart from './components/LineChart'
|
||||
import RaddarChart from './components/RaddarChart'
|
||||
import PieChart from './components/PieChart'
|
||||
import BarChart from './components/BarChart'
|
||||
// import TransactionTable from './components/TransactionTable'
|
||||
import TodoList from './components/TodoList'
|
||||
import BoxCard from './components/BoxCard'
|
||||
import RecentItems from '@/components/ADempiere/RecentItems'
|
||||
import Favorites from '@/components/ADempiere/Favorites'
|
||||
import PendingDocuments from '@/components/ADempiere/PendingDocuments'
|
||||
|
||||
const lineChartData = {
|
||||
newVisitis: {
|
||||
expectedData: [100, 120, 161, 134, 105, 160, 165],
|
||||
actualData: [120, 82, 91, 154, 162, 140, 145]
|
||||
},
|
||||
messages: {
|
||||
expectedData: [200, 192, 120, 144, 160, 130, 140],
|
||||
actualData: [180, 160, 151, 106, 145, 150, 130]
|
||||
},
|
||||
purchases: {
|
||||
expectedData: [80, 100, 121, 104, 105, 90, 100],
|
||||
actualData: [120, 90, 100, 138, 142, 130, 130]
|
||||
},
|
||||
shoppings: {
|
||||
expectedData: [130, 140, 141, 142, 145, 150, 160],
|
||||
actualData: [120, 82, 91, 154, 162, 140, 130]
|
||||
}
|
||||
}
|
||||
import Dashboard from '@/components/ADempiere/Dashboard'
|
||||
|
||||
export default {
|
||||
name: 'DashboardAdmin',
|
||||
components: {
|
||||
GithubCorner,
|
||||
PanelGroup,
|
||||
LineChart,
|
||||
RaddarChart,
|
||||
PieChart,
|
||||
BarChart,
|
||||
// TransactionTable,
|
||||
TodoList,
|
||||
BoxCard,
|
||||
RecentItems,
|
||||
Favorites,
|
||||
PendingDocuments
|
||||
Dashboard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lineChartData: lineChartData.newVisitis
|
||||
roleUuid: this.$store.getters.getRoleUuid,
|
||||
dashboardList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getterDashboard() {
|
||||
return this.$store.getters.getDashboardByRole(this.roleUuid)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getDashboardListFromServer()
|
||||
},
|
||||
methods: {
|
||||
handleSetLineChartData(type) {
|
||||
this.lineChartData = lineChartData[type]
|
||||
getDashboardListFromServer() {
|
||||
if (this.getterDashboard) {
|
||||
this.dashboardList = this.getterDashboard
|
||||
} else {
|
||||
this.$store.dispatch('listDashboard', this.roleUuid)
|
||||
.then(response => {
|
||||
this.dashboardList = response.dashboardList
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue