Add Export Window Record (#168)

* Add Export Window Record

* Remove console.log

* unnecessary message

* add javascript class for exporter

* rename function

* rename file

* Add contexMenu to table

* import changes

* correcting translations

* add translation when exporting file...

* add a computed property to the Json array

* Add Traslation to Option Format Export

* remove validation

* Restore File

* restore file Export

* restore file Export

* Update Export2Excel.js
pull/3759/head
elsiosanchez 2019-12-02 12:36:06 -04:00 committed by Yamel Senih
parent f82d0a49b3
commit 929301579c
10 changed files with 465 additions and 26 deletions

View File

@ -1,6 +1,6 @@
<template>
<div class="container-submenu container-context-menu">
<el-menu :default-active="activeMenu" :router="false" class="el-menu-demo" mode="horizontal" menu-trigger="hover" unique-opened>
<el-menu :default-active="activeMenu" :router="false" class="el-menu-demo" mode="horizontal" menu-trigger="hover" unique-opened @select="typeFormat">
<template>
<el-submenu v-if="relations !== undefined && relations.length" class="el-menu-item" index="1">
<template slot="title">
@ -35,15 +35,34 @@
{{ $t('components.contextMenuDownload') }}
</a>
</el-menu-item>
<el-submenu
v-if="getDataSelection.length > 0 && panelType === 'browser'"
:disabled="Boolean(getDataSelection.length < 1)"
index="xlsx"
@click.native="exporBrowser('xlsx')"
>
<template slot="title">{{ $t('components.contextMennuWindowReport') }}</template>
<template v-for="(format, index) in option">
<el-menu-item :key="index" :index="index">
{{ format }}
</el-menu-item>
</template>
</el-submenu>
<el-submenu
v-if="panelType === 'window'"
index="xlsx"
@click.native="exporWindow('xlsx')"
>
<template slot="title">{{ $t('components.contextMennuWindowReport') }}</template>
<template v-for="(format, index) in option">
<el-menu-item :key="index" :index="index">
{{ format }}
</el-menu-item>
</template>
</el-submenu>
<el-menu-item v-show="$route.name === 'Report Viewer'" index="9" @click="$router.push({ name: ROUTES.PRINT_FORMAT_SETUP_WINDOW.uuid })">
{{ $t('components.contextMenuPrintFormatSetup') }}
</el-menu-item>
<el-menu-item v-if="getDataSelection.length > 0 && panelType === 'browser'" index="6" @click="exporBrowser">
{{ $t('components.contextMennuExport') }}
</el-menu-item>
<el-menu-item v-if="panelType === 'window'" index="7" @click="exporBrowser">
{{ $t('components.contextMennuWindowReport') }}
</el-menu-item>
<el-menu-item v-if="panelType !== 'process'" index="8" @click="refreshData">
{{ $t('components.contextMenuRefresh') }}
</el-menu-item>

View File

@ -1,6 +1,7 @@
import { showNotification } from '@/utils/ADempiere/notification'
import Item from './items'
import { convertFieldListToShareLink } from '@/utils/ADempiere/valueUtil'
import { supportedTypes, exportFileFromJson } from '@/utils/ADempiere/exportUtil'
import ROUTES from '@/utils/ADempiere/zoomWindow'
export const contextMixin = {
@ -51,6 +52,7 @@ export const contextMixin = {
data() {
return {
actions: [],
option: supportedTypes,
references: [],
file: this.$store.getters.getProcessResult.download,
downloads: this.$store.getters.getProcessResult.url,
@ -133,6 +135,17 @@ export const contextMixin = {
}
})
},
getterDataRecordsAll() {
return this.$store.getters.getDataRecordAndSelection(this.containerUuid).record
},
getDataRecord() {
var record = this.getterDataRecordsAll.filter(fieldItem => {
if (this.recordUuid === fieldItem.UUID) {
return fieldItem
}
})
return record
},
getterDataLog() {
if (this.panelType === 'window') {
return this.$store.getters.getDataLog(this.containerUuid, this.recordUuid)
@ -224,18 +237,38 @@ export const contextMixin = {
this.isReferencesLoaded = false
}
},
exporBrowser() {
import('@/vendor/Export2Excel').then(excel => {
const tHeader = this.getterFieldListHeader
const filterVal = this.getterFieldListValue
const list = this.getDataSelection
const data = this.formatJson(filterVal, list)
excel.export_json_to_excel({
header: tHeader,
data,
filename: ''
})
})
typeFormat(key) {
Object.keys(supportedTypes).forEach(type => {
if (type === key && (this.panelType === 'window')) {
this.exporWindow(key)
} else if (type === key && (this.panelType === 'browser')) {
this.exporBrowser(key)
}
})
},
exporBrowser(key) {
const tHeader = this.getterFieldListHeader
const filterVal = this.getterFieldListValue
const list = this.getDataSelection
const data = this.formatJson(filterVal, list)
exportFileFromJson({
header: tHeader,
data,
filename: '',
exportType: key
})
},
exporWindow(key) {
const tHeader = this.getterFieldListHeader
const filterVal = this.getterFieldListValue
const list = this.getDataRecord
const data = this.formatJson(filterVal, list)
exportFileFromJson({
header: tHeader,
data,
filename: '',
exportType: key
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => v[j]))

View File

@ -0,0 +1,163 @@
<template>
<el-menu :collapse="isCollapse" class="el-menu-demo" @select="typeFormat">
<el-submenu
index="xlsx"
>
<template slot="title">{{ $t('components.contextMennuWindowReport') }}</template>
<template v-for="(format, index) in option">
<el-menu-item :key="index" :index="index">
{{ format }}
</el-menu-item>
</template>
</el-submenu>
<el-menu-item index="eliminar" style="padding-left: 36px;">
{{ $t('window.deleteRecord') }}
</el-menu-item>
</el-menu>
</template>
<script>
import { supportedTypes, exportFileFromJson } from '@/utils/ADempiere/exportUtil'
export default {
name: 'ContextMenu',
props: {
parentUuid: {
type: String,
default: undefined
},
containerUuid: {
type: String,
required: true
},
panelType: {
type: String,
default: 'window'
},
isOption: {
type: Object,
default: () => {}
}
},
data() {
return {
option: supportedTypes,
isCollapse: true,
visible: false
}
},
computed: {
getterFieldList() {
return this.$store.getters.getFieldsListFromPanel(this.containerUuid)
},
getterFieldListHeader() {
var header = this.getterFieldList.filter(fieldItem => {
const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic
if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) {
return fieldItem.name
}
})
return header.map(fieldItem => {
return fieldItem.name
})
},
getterFieldListValue() {
var value = this.getterFieldList.filter(fieldItem => {
const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic
if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) {
return fieldItem
}
})
return value.map(fieldItem => {
if (fieldItem.componentPath === 'FieldSelect') {
return 'DisplayColumn_' + fieldItem.columnName
} else {
return fieldItem.columnName
}
})
},
gettersRecordContextMenu() {
var record = []
var recordTable = this.isOption
record.push(recordTable)
return record
},
getDataSelection() {
return this.$store.getters.getDataRecordSelection(this.containerUuid)
}
},
methods: {
classTableMenu() {
if (this.isMobile) {
return 'menu-table-mobile'
} else if (this.$store.state.app.sidebar.opened) {
return 'menu-table'
}
return 'menu-table'
},
typeFormat(key, keyPath) {
if (key === 'eliminar') {
this.rowMenu()
} else {
this.exporRecordTable(key)
}
this.$store.dispatch('showMenuTable', {
isShowedTable: false
})
},
exporRecordTable(key) {
const Header = this.getterFieldListHeader
const filterVal = this.getterFieldListValue
const list = this.gettersRecordContextMenu
const data = this.formatJson(filterVal, list)
exportFileFromJson({
header: Header,
data,
filename: '',
exportType: key
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => v[j]))
},
rowMenu() {
this.$store.dispatch('deleteEntity', {
parentUuid: this.parentUuid,
containerUuid: this.containerUuid,
recordUuid: this.isOption.UUID,
panelType: this.panelType,
isNewRecord: 'deleteEntity' === 'resetPanelToNew'
})
}
}
}
</script>
<style>
.el-menu--vertical .nest-menu .el-submenu>.el-submenu__title:hover, .el-menu--vertical .el-menu-item:hover {
background-color: #ffffff !important;
background: #ffffff !important;
}
.el-menu--collapse {
width: auto;
}
.el-menu-item:hover {
background-color: #ffffff !important
}
.hover {
background-color: initial !important;
}
.el-menu-item {
height: 56px;
line-height: 56px;
font-size: 14px;
color: #303133;
padding: 0 20px;
list-style: none;
cursor: pointer;
position: relative;
-webkit-transition: border-color .3s, background-color .3s, color .3s;
transition: border-color .3s, background-color .3s, color .3s;
-webkit-box-sizing: border-box;
box-sizing: border-box;
white-space: nowrap;
}
</style>

View File

@ -22,7 +22,7 @@
</el-collapse>
<div>
<div v-if="!isMobile">
<el-menu :default-active="menuTable" :class="classTableMenu + ' menu-table-container'" mode="horizontal">
<el-menu :default-active="menuTable" :class="classTableMenu + ' menu-table-container'" mode="horizontal" @select="typeFormat">
<el-submenu index="2">
<template slot="title">
<i class="el-icon-more" />
@ -43,6 +43,17 @@
>
{{ $t('table.dataTable.deleteSelection') }}
</el-menu-item>
<el-submenu
:disabled="Boolean(getDataSelection.length < 1)"
index="xlsx"
>
<template slot="title">{{ $t('table.dataTable.exportRecordTable') }}</template>
<template v-for="(format, index) in option">
<el-menu-item :key="index" :index="index">
{{ format }}
</el-menu-item>
</template>
</el-submenu>
<el-menu-item index="optional" @click="optionalPanel()">
{{ $t('components.filterableItems') }}
</el-menu-item>
@ -109,6 +120,18 @@
>
{{ $t('table.dataTable.deleteSelection') }}
</el-menu-item>
<el-submenu
v-if="isPanelWindow"
:disabled="Boolean(getDataSelection.length < 1)"
index="xlsx"
>
<template slot="title">{{ $t('table.dataTable.exportRecordTable') }}</template>
<template v-for="(format, index) in option">
<el-menu-item :key="index" :index="index">
{{ format }}
</el-menu-item>
</template>
</el-submenu>
<el-menu-item index="optional" @click="optionalPanel()">
{{ $t('components.filterableItems') }}
</el-menu-item>
@ -185,6 +208,16 @@
</div>
</el-header>
<el-main style="padding: 0px !important; overflow: hidden;">
<context-menu
v-if="isParent"
v-show="getShowContextMenuTable"
:style="{left:left+'px',top:top+'px'}"
class="contextmenu"
:container-uuid="containerUuid"
:parent-uuid="parentUuid"
:panel-type="panelType"
:is-option="isOption"
/>
<el-table
ref="multipleTable"
v-loading="$route.query.action !== 'create-new' && isLoaded"
@ -205,6 +238,8 @@
@row-dblclick="handleRowDblClick"
@select="handleSelection"
@select-all="handleSelectionAll"
@row-contextmenu="rowMenu"
@contextmenu.prevent.native="block"
>
<el-table-column
v-if="isTableSelection"
@ -282,12 +317,14 @@ import FieldDefinition from '@/components/ADempiere/Field'
import Sortable from 'sortablejs'
import FilterColumns from '@/components/ADempiere/DataTable/filterColumns'
import FixedColumns from '@/components/ADempiere/DataTable/fixedColumns'
import ContextMenu from '@/components/ADempiere/DataTable/contextMenu'
import IconElement from '@/components/ADempiere/IconElement'
import { formatDate } from '@/filters/ADempiere'
import MainPanel from '@/components/ADempiere/Panel'
import { sortFields } from '@/utils/ADempiere'
import { FIELD_READ_ONLY_FORM } from '@/components/ADempiere/Field/references'
import { fieldIsDisplayed } from '@/utils/ADempiere'
import { supportedTypes, exportFileFromJson } from '@/utils/ADempiere/exportUtil'
import evaluator from '@/utils/ADempiere/evaluator'
export default {
@ -296,6 +333,7 @@ export default {
FieldDefinition,
FilterColumns,
FixedColumns,
ContextMenu,
IconElement,
MainPanel
},
@ -335,8 +373,13 @@ export default {
},
data() {
return {
top: 0,
left: 0,
isOption: {},
visible: this.getShowContextMenuTable,
searchTable: '', // text from search
defaultMaxPagination: 100,
option: supportedTypes,
menuTable: '1',
activeName: '',
isOptional: false,
@ -352,6 +395,38 @@ export default {
}
},
computed: {
getShowContextMenuTable() {
return this.$store.getters.getShowContextMenuTable
},
getterFieldList() {
return this.$store.getters.getFieldsListFromPanel(this.containerUuid)
},
getterFieldListHeader() {
var header = this.getterFieldList.filter(fieldItem => {
const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic
if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) {
return fieldItem.name
}
})
return header.map(fieldItem => {
return fieldItem.name
})
},
getterFieldListValue() {
var value = this.getterFieldList.filter(fieldItem => {
const isDisplayed = fieldItem.isDisplayed || fieldItem.isDisplayedFromLogic
if (fieldItem.isActive && isDisplayed && !fieldItem.isKey) {
return fieldItem
}
})
return value.map(fieldItem => {
if (fieldItem.componentPath === 'FieldSelect') {
return 'DisplayColumn_' + fieldItem.columnName
} else {
return fieldItem.columnName
}
})
},
isMobile() {
return this.$store.state.app.device === 'mobile'
},
@ -504,6 +579,15 @@ export default {
return false
}
},
watch: {
visible(value) {
if (value) {
document.body.addEventListener('click', this.closeMenu)
} else {
document.body.removeEventListener('click', this.closeMenu)
}
}
},
created() {
this.getPanel()
},
@ -516,6 +600,56 @@ export default {
}
},
methods: {
closeMenu() {
this.$store.dispatch('showMenuTable', {
isShowedTable: false
})
},
block() {
return false
},
rowMenu(row, column, event) {
const menuMinWidth = 105
const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
const offsetWidth = this.$el.offsetWidth // container width
const maxLeft = offsetWidth - menuMinWidth // left boundary
const left = event.clientX - offsetLeft + 15 // 15: margin right
if (left > maxLeft) {
this.left = maxLeft
} else {
this.left = left
}
this.top = event.clientY - 100
this.isOption = row
this.visible = true
this.$store.dispatch('showMenuTable', {
isShowedTable: true
})
},
typeFormat(key, keyPath) {
Object.keys(supportedTypes).forEach(type => {
if (type === key) {
this.exporRecordTable(key)
}
})
},
exporRecordTable(key) {
const Header = this.getterFieldListHeader
const filterVal = this.getterFieldListValue
const list = this.getDataSelection
const data = this.formatJson(filterVal, list)
exportFileFromJson({
header: Header,
data,
filename: '',
exportType: key
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => v[j]))
},
sortFields,
handleChange(val) {
val = !val
@ -964,6 +1098,27 @@ export default {
</script>
<style lang="scss">
.contextmenu {
margin: 0;
background: #fff;
z-index: 3000;
position: absolute;
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
font-size: 12px;
font-weight: 400;
color: #333;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
li {
margin: 0;
padding: 7px 16px;
cursor: pointer;
&:hover {
background: #eee;
}
}
}
.el-table-row {
.hover-row {
background-color: black;

View File

@ -123,7 +123,7 @@ export default {
contextMenuShareLink: 'Share Link',
contextMenuRefresh: 'Refresh',
contextMennuExport: 'Export Smart Browser',
contextMennuWindowReport: 'Window Report ',
contextMennuWindowReport: 'Export Records',
contextMenuPrintFormatSetup: 'Print Format Setup',
dateStartPlaceholder: 'Start date',
dateEndPlaceholder: 'End date',
@ -159,6 +159,14 @@ export default {
reportView: 'Report Views',
printFormat: 'Print Formats'
},
report: {
ExportXlsx: '(xlsx) Excel File Extension',
ExportXls: '(xls) Excel File',
ExporXml: '(xml) Extensible Markup Language File',
ExporCsv: '(csv) Archivo separado por coma',
ExportTxt: '(txt) Tab Delimited Text File',
ExportHtml: '(html) Hypertext Markup Language'
},
table: {
ProcessActivity: {
name: 'Name',
@ -180,6 +188,7 @@ export default {
advancedQuery: 'Advanced Query',
showOnlyMandatoryColumns: 'Show Only Mandatory Columns',
showAllAvailableColumns: 'Show All Available Columns',
exportRecordTable: 'Export Selected Records',
showTotal: 'Show Totals',
hiddenTotal: 'Hidden Totals'
},

View File

@ -119,7 +119,7 @@ export default {
contextMenuShareLink: 'Compartir Link',
contextMenuRefresh: 'Actualizar',
contextMennuExport: 'Exportar Smart Browser',
contextMennuWindowReport: 'Informe de Ventana',
contextMennuWindowReport: 'Exportar Registro',
contextMenuPrintFormatSetup: 'Configurar Formato de Impresión',
RunProcess: 'Ejecutar',
ChangeParameters: 'Cambiar Parametros',
@ -159,6 +159,14 @@ export default {
reportView: 'Vistas de Reporte',
printFormat: 'Formatos de Impresión'
},
report: {
ExportXlsx: '(xlsx) Extencion de Archivo Excel',
ExportXls: '(xls) Archivo Excel ',
ExporXml: '(xml) Archivo Lenguaje de marcas Extensible',
ExporCsv: '(csv) Archivo Separado por Coma',
ExportTxt: '(txt) Archivo de Texto Delimitado por Tabuladores',
ExportHtml: '(html) Lenguaje de Marcas de Hipertexto'
},
table: {
ProcessActivity: {
Name: 'Nombre',
@ -179,6 +187,8 @@ export default {
deleteSelection: 'Eliminar Registros Seleccionados',
advancedQuery: 'Consulta Avanzada',
showOnlyMandatoryColumns: 'Mostrar Solo Columnas Obligatorias',
showAllAvailableColumns: 'Mostrar Todas Columnas Disponibles',
exportRecordTable: 'Exportar Registros Seleccionados',
showTotal: 'Mostrar Totales',
hiddenTotal: 'Ocultar Totales'
},

View File

@ -243,7 +243,6 @@ const processControl = {
if (reportType !== 'pdf' && reportType !== 'html') {
link.click()
}
// Report views List to context menu
var reportViewList = {
name: language.t('views.reportView'),

View File

@ -8,7 +8,9 @@ const utils = {
widthLayout: 0,
tempShareLink: '',
oldAction: undefined,
reportType: ''
reportType: '',
isShowedTable: false,
recordUuidTable: 0
},
mutations: {
setWidth(state, width) {
@ -23,9 +25,15 @@ const utils = {
setSplitHeight(state, splitHeight) {
state.splitHeight = splitHeight
},
showMenuTable(state, isShowedTable) {
state.isShowedTable = isShowedTable
},
setSplitHeightTop(state, splitHeightTop) {
state.splitHeightTop = splitHeightTop
},
setRecordUuidMenu(state, recordUuidTable) {
state.recordUuidTable = recordUuidTable
},
setTempShareLink(state, payload) {
state.tempShareLink = payload
},
@ -46,12 +54,18 @@ const utils = {
setHeight({ commit }, height) {
commit('setHeigth', height)
},
showMenuTable({ commit }, isShowedTable) {
commit('showMenuTable', isShowedTable)
},
setSplitHeight({ commit }, splitHeight) {
commit('setSplitHeight', splitHeight)
},
setSplitHeightTop({ commit }, splitHeightTop) {
commit('setSplitHeightTop', splitHeightTop)
},
setRecordUuidMenu({ commit }, recordUuidTable) {
commit('setRecordUuidMenu', recordUuidTable)
},
changeShowedDetail({ dispatch }, params) {
if (params.panelType === 'window') {
dispatch('changeShowedDetailWindow', params)
@ -87,6 +101,13 @@ const utils = {
getSplitHeightTop: (state) => {
return state.getSplitHeightTop
},
getRecordUuidMenu: (state) => {
return state.recordUuidTable
},
getShowContextMenuTable: (state) => {
const menu = state.isShowedTable.isShowedTable
return menu
},
getSplitHeight: (state) => {
const split = state.splitHeight
var panelHeight = 0

View File

@ -369,11 +369,10 @@ const windowControl = {
deleteEntity({ dispatch, rootGetters }, parameters) {
return new Promise((resolve, reject) => {
const panel = rootGetters.getPanel(parameters.containerUuid)
const recordUuid = rootGetters.getUuid(parameters.containerUuid)
deleteEntity({
tableName: panel.tableName,
recordUuid: recordUuid
recordUuid: parameters.recordUuid
})
.then(response => {
const oldRoute = router.app._route

View File

@ -0,0 +1,31 @@
import { export_json_to_excel } from '@/vendor/Export2Excel'
import language from '@/lang'
export const supportedTypes = {
xlsx: language.t('report.ExportXlsx'),
xls: language.t('report.ExportXls'),
xml: language.t('report.ExporXml'),
csv: language.t('report.ExporCsv'),
txt: language.t('report.ExportTxt'),
html: language.t('report.ExportHtml')
}
export function exportFileFromJson({
header,
data,
exportType
}) {
var Json = data.map(dataJson => {
Object.keys(dataJson).forEach(key => {
if (typeof dataJson[key] === 'boolean') {
dataJson[key] = dataJson[key] ? language.t('components.switchActiveText') : language.t('components.switchInactiveText')
}
})
return dataJson
})
export_json_to_excel({
header: header,
data: Json,
filename: '',
bookType: exportType
})
}