mirror of
https://github.com/frappe/books.git
synced 2024-12-22 19:09:01 +00:00
feat: Reports
This commit is contained in:
parent
bd5d812d77
commit
86993edee2
@ -5,7 +5,8 @@ export default {
|
||||
title: _('Item'),
|
||||
columns: [
|
||||
'name',
|
||||
'unit',
|
||||
'tax',
|
||||
'rate',
|
||||
'tax'
|
||||
]
|
||||
}
|
||||
|
@ -95,39 +95,48 @@ const viewConfig = {
|
||||
return [
|
||||
{
|
||||
label: 'Date',
|
||||
fieldtype: 'Date'
|
||||
fieldtype: 'Date',
|
||||
fieldname: 'date'
|
||||
},
|
||||
{
|
||||
label: 'Account',
|
||||
fieldtype: 'Link'
|
||||
fieldtype: 'Link',
|
||||
fieldname: 'account'
|
||||
},
|
||||
{
|
||||
label: 'Debit',
|
||||
fieldtype: 'Currency'
|
||||
fieldtype: 'Currency',
|
||||
fieldname: 'debit'
|
||||
},
|
||||
{
|
||||
label: 'Credit',
|
||||
fieldtype: 'Currency'
|
||||
fieldtype: 'Currency',
|
||||
fieldname: 'credit'
|
||||
},
|
||||
{
|
||||
label: 'Balance',
|
||||
fieldtype: 'Currency'
|
||||
fieldtype: 'Currency',
|
||||
fieldname: 'balance'
|
||||
},
|
||||
{
|
||||
label: 'Reference Type',
|
||||
fieldtype: 'Data'
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'referenceType'
|
||||
},
|
||||
{
|
||||
label: 'Reference Name',
|
||||
fieldtype: 'Data'
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'referenceName'
|
||||
},
|
||||
{
|
||||
label: 'Party',
|
||||
fieldtype: 'Link'
|
||||
fieldtype: 'Link',
|
||||
fieldname: 'party'
|
||||
},
|
||||
{
|
||||
label: 'Description',
|
||||
fieldtype: 'Data'
|
||||
fieldtype: 'Data',
|
||||
fieldname: 'description'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@ -14,21 +14,24 @@ export default {
|
||||
ratio: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
gap: String
|
||||
},
|
||||
computed: {
|
||||
style() {
|
||||
let obj = {};
|
||||
if (this.columnCount) {
|
||||
return {
|
||||
'grid-template-columns': `repeat(${this.columnCount}, 1fr)`
|
||||
}
|
||||
obj['grid-template-columns'] = `repeat(${this.columnCount}, 1fr)`;
|
||||
}
|
||||
if (this.ratio.length) {
|
||||
return {
|
||||
'grid-template-columns': this.ratio.map(r => `${r}fr`).join(' ')
|
||||
}
|
||||
obj['grid-template-columns'] = this.ratio.map(r => `${r}fr`).join(' ');
|
||||
}
|
||||
if (this.gap) {
|
||||
obj['grid-gap'] = this.gap;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<div class="px-8 pb-8 mt-2 text-sm flex flex-col justify-between">
|
||||
<div>
|
||||
<Row class="text-gray-700" :columnCount="columns.length">
|
||||
<Row class="text-gray-700" :columnCount="columns.length" gap="1rem">
|
||||
<div
|
||||
v-for="column in columns"
|
||||
:key="column.label"
|
||||
class="py-4 truncate"
|
||||
:class="['Float', 'Currency'].includes(column.fieldtype) ? 'text-right pr-10' : ''"
|
||||
:class="['Float', 'Currency'].includes(column.fieldtype) ? 'text-right' : ''"
|
||||
>{{ column.label }}</div>
|
||||
</Row>
|
||||
<Row
|
||||
gap="1rem"
|
||||
class="cursor-pointer text-gray-900 hover:text-gray-600"
|
||||
v-for="doc in data"
|
||||
:key="doc.name"
|
||||
@ -19,14 +20,19 @@
|
||||
<ListCell
|
||||
v-for="column in columns"
|
||||
:key="column.label"
|
||||
:class="['Float', 'Currency'].includes(column.fieldtype) ? 'text-right pr-10' : ''"
|
||||
:class="['Float', 'Currency'].includes(column.fieldtype) ? 'text-right' : ''"
|
||||
:doc="doc"
|
||||
:column="column"
|
||||
></ListCell>
|
||||
</Row>
|
||||
</div>
|
||||
<div class="flex items-center justify-center">
|
||||
<Button :icon="true" :class="start == 0 && 'text-gray-600'" :disabled="start == 0" @click="prevPage">
|
||||
<Button
|
||||
:icon="true"
|
||||
:class="start == 0 && 'text-gray-600'"
|
||||
:disabled="start == 0"
|
||||
@click="prevPage"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
@ -45,7 +51,12 @@
|
||||
<span class="text-gray-600">of</span>
|
||||
<span class="font-medium">{{ totalCount }}</span>
|
||||
</div>
|
||||
<Button :icon="true" :class="start + pageLength >= totalCount && 'text-gray-600'" :disabled="start + pageLength >= totalCount" @click="nextPage">
|
||||
<Button
|
||||
:icon="true"
|
||||
:class="start + pageLength >= totalCount && 'text-gray-600'"
|
||||
:disabled="start + pageLength >= totalCount"
|
||||
@click="nextPage"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
|
91
src/pages/Report.vue
Normal file
91
src/pages/Report.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<PageHeader>
|
||||
<h1 slot="title" class="text-xl font-bold">{{ report.title }}</h1>
|
||||
<template slot="actions">
|
||||
<SearchBar class="ml-2" />
|
||||
</template>
|
||||
</PageHeader>
|
||||
<div class="flex flex-col flex-1 px-8 mt-4">
|
||||
<Row :columnCount="columns.length" gap="1rem">
|
||||
<div
|
||||
class="text-gray-600 text-sm truncate py-4"
|
||||
v-for="column in columns"
|
||||
:key="column.label"
|
||||
>{{ column.label }}</div>
|
||||
</Row>
|
||||
<div class="flex-1 overflow-auto">
|
||||
<Row v-for="row in rows" :columnCount="columns.length" gap="1rem">
|
||||
<div
|
||||
class="text-gray-900 text-sm truncate py-4"
|
||||
v-for="column in columns"
|
||||
:key="column.label"
|
||||
v-html="row[column.fieldname]"
|
||||
></div>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import frappe from 'frappejs';
|
||||
import PageHeader from '@/components/PageHeader';
|
||||
import Button from '@/components/Button';
|
||||
import SearchBar from '@/components/SearchBar';
|
||||
import Row from '@/components/Row';
|
||||
import reportViewConfig from '@/../reports/view';
|
||||
|
||||
export default {
|
||||
name: 'Report',
|
||||
props: ['reportName'],
|
||||
components: {
|
||||
PageHeader,
|
||||
Button,
|
||||
SearchBar,
|
||||
Row
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rows: [],
|
||||
columns: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.columns = this.report.getColumns();
|
||||
this.fetchReportData();
|
||||
},
|
||||
methods: {
|
||||
async fetchReportData() {
|
||||
let data = await frappe.call({
|
||||
method: this.report.method,
|
||||
args: {
|
||||
fromDate: '2019-09-01',
|
||||
toDate: '2019-10-31'
|
||||
}
|
||||
});
|
||||
|
||||
let rows, columns;
|
||||
if (data.rows) {
|
||||
rows = data.rows;
|
||||
} else {
|
||||
rows = data;
|
||||
}
|
||||
|
||||
if (data.columns) {
|
||||
this.columns = this.report.getColumns(data);
|
||||
}
|
||||
|
||||
if (!rows) {
|
||||
rows = [];
|
||||
}
|
||||
|
||||
this.rows = rows;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
report() {
|
||||
return reportViewConfig[this.reportName];
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -7,7 +7,7 @@ import FormView from '@/pages/FormView/FormView';
|
||||
import PrintView from '@/pages/PrintView';
|
||||
import QuickEditForm from '@/pages/QuickEditForm';
|
||||
|
||||
import Report from '@/pages/Report';
|
||||
import Report from '@/pages/Report.vue';
|
||||
import reportViewConfig from '../reports/view';
|
||||
|
||||
import DataImport from '@/pages/DataImport';
|
||||
@ -29,7 +29,7 @@ const routes = [
|
||||
component: Dashboard
|
||||
},
|
||||
{
|
||||
path: '/edit/SalesInvoice/:name',
|
||||
path: '/edit/:doctype/:name',
|
||||
name: 'InvoiceForm',
|
||||
components: {
|
||||
default: InvoiceForm,
|
||||
@ -74,14 +74,7 @@ const routes = [
|
||||
path: '/report/:reportName',
|
||||
name: 'Report',
|
||||
component: Report,
|
||||
props: route => {
|
||||
const { reportName } = route.params;
|
||||
return {
|
||||
reportName,
|
||||
reportConfig: reportViewConfig[reportName] || null,
|
||||
filters: route.query
|
||||
};
|
||||
}
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: '/data-import',
|
||||
@ -119,6 +112,6 @@ const routes = [
|
||||
];
|
||||
|
||||
let router = new Router({ routes });
|
||||
router.replace('/list/Item');
|
||||
router.replace('/report/general-ledger');
|
||||
|
||||
export default router;
|
||||
|
Loading…
Reference in New Issue
Block a user