mirror of
https://github.com/frappe/books.git
synced 2024-11-10 07:40:55 +00:00
Render ListView based on listConfig
This commit is contained in:
parent
550c2708d2
commit
bd3b266a69
@ -26,9 +26,8 @@ module.exports = {
|
||||
fieldtype: 'Link',
|
||||
target: 'Party',
|
||||
required: 1,
|
||||
getFilters: (query, control) => {
|
||||
getFilters: (query) => {
|
||||
return {
|
||||
keywords: ['like', query],
|
||||
customer: 1
|
||||
};
|
||||
}
|
||||
@ -38,7 +37,7 @@ module.exports = {
|
||||
label: 'Account',
|
||||
fieldtype: 'Link',
|
||||
target: 'Account',
|
||||
formula: (doc) => doc.getFrom('Party', doc.customer , 'default_account'),
|
||||
formula: (doc) => doc.getFrom('Party', doc.customer , 'defaultAccount'),
|
||||
getFilters: (query, control) => {
|
||||
return {
|
||||
keywords: ['like', query],
|
||||
@ -145,37 +144,5 @@ module.exports = {
|
||||
await form.$formModal.open(payment);
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
listSettings: {
|
||||
getFields(list) {
|
||||
return ['name', 'customer', 'grandTotal', 'submitted'];
|
||||
},
|
||||
|
||||
getRowHTML(list, data) {
|
||||
return `<div class='col-3'>${list.getNameHTML(data)}</div>
|
||||
<div class='col-4 text-muted'>${data.customer}</div>
|
||||
<div class='col-4 text-muted text-right'>${frappe.format(data.grandTotal, 'Currency')}</div>`;
|
||||
}
|
||||
},
|
||||
|
||||
listView: {
|
||||
columns: [
|
||||
'customer',
|
||||
{
|
||||
label: 'Status',
|
||||
getValue(doc) {
|
||||
return doc.submitted ? 'Paid' : 'Pending';
|
||||
}
|
||||
},
|
||||
'grandTotal',
|
||||
'date',
|
||||
{
|
||||
label: 'INV #',
|
||||
getValue(doc) {
|
||||
return doc.name;
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
23
models/doctype/Invoice/InvoiceList.js
Normal file
23
models/doctype/Invoice/InvoiceList.js
Normal file
@ -0,0 +1,23 @@
|
||||
import { _ } from 'frappejs/utils';
|
||||
|
||||
export default {
|
||||
doctype: 'Invoice',
|
||||
title: _('Invoice'),
|
||||
columns: [
|
||||
'customer',
|
||||
{
|
||||
label: 'Status',
|
||||
getValue(doc) {
|
||||
return doc.submitted ? 'Paid' : 'Pending';
|
||||
}
|
||||
},
|
||||
'grandTotal',
|
||||
'date',
|
||||
{
|
||||
label: 'INV #',
|
||||
getValue(doc) {
|
||||
return doc.name;
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -80,11 +80,5 @@ module.exports = {
|
||||
{ fields: ['tax'] }
|
||||
]
|
||||
}
|
||||
],
|
||||
listView: {
|
||||
columns: [
|
||||
'name',
|
||||
'description'
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
10
models/doctype/Item/ItemList.js
Normal file
10
models/doctype/Item/ItemList.js
Normal file
@ -0,0 +1,10 @@
|
||||
import { _ } from 'frappejs/utils';
|
||||
|
||||
export default {
|
||||
doctype: 'Item',
|
||||
title: _('Item'),
|
||||
columns: [
|
||||
'name',
|
||||
'description'
|
||||
]
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
const BaseList = require('frappejs/client/view/list');
|
||||
const frappe = require('frappejs');
|
||||
import { _ } from 'frappejs/utils';
|
||||
|
||||
module.exports = class CustomerList extends BaseList {
|
||||
constructor({doctype, parent, fields, page}) {
|
||||
super({doctype: 'Party', parent: parent, fields: fields, page: page});
|
||||
}
|
||||
getFilters() {
|
||||
let filters = super.getFilters();
|
||||
filters.customer = 1;
|
||||
return filters;
|
||||
}
|
||||
export default {
|
||||
doctype: 'Party',
|
||||
title: _('Customer'),
|
||||
columns: [
|
||||
'name'
|
||||
],
|
||||
filters: {
|
||||
customer: 1
|
||||
}
|
||||
}
|
@ -14,13 +14,12 @@ module.exports = {
|
||||
"required": 1
|
||||
},
|
||||
{
|
||||
fieldname: 'default_account',
|
||||
fieldname: 'defaultAccount',
|
||||
label: 'Default Account',
|
||||
fieldtype: 'Link',
|
||||
target: 'Account',
|
||||
getFilters: (query, control) => {
|
||||
return {
|
||||
keywords: ['like', query],
|
||||
isGroup: 0,
|
||||
accountType: 'Receivable'
|
||||
};
|
||||
@ -48,12 +47,5 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
listView: {
|
||||
columns: [
|
||||
'name'
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ export default {
|
||||
},
|
||||
{
|
||||
label: 'Customers',
|
||||
route: '/list/Party'
|
||||
route: '/list/Customer'
|
||||
},
|
||||
{
|
||||
label: 'Items',
|
||||
|
@ -52,30 +52,33 @@ export default {
|
||||
return frappe.getMeta(this.doctype);
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
if (!this.name) return;
|
||||
try {
|
||||
this.doc = await frappe.getDoc(this.doctype, this.name);
|
||||
|
||||
if (this.doc._notInserted && this.meta.fields.map(df => df.fieldname).includes('name')) {
|
||||
// For a user editable name field,
|
||||
// it should be unset since it is autogenerated
|
||||
this.doc.set('name', '');
|
||||
}
|
||||
|
||||
if (this.defaultValues) {
|
||||
for (let fieldname in this.defaultValues) {
|
||||
const value = this.defaultValues[fieldname];
|
||||
this.doc.set(fieldname, value);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
this.notFound = true;
|
||||
}
|
||||
this.setLinks();
|
||||
this.doc.on('change', this.setLinks);
|
||||
created() {
|
||||
this.loadDoc();
|
||||
},
|
||||
methods: {
|
||||
async loadDoc() {
|
||||
if (!this.name) return;
|
||||
try {
|
||||
this.doc = await frappe.getDoc(this.doctype, this.name);
|
||||
|
||||
if (this.doc._notInserted && this.meta.fields.map(df => df.fieldname).includes('name')) {
|
||||
// For a user editable name field,
|
||||
// it should be unset since it is autogenerated
|
||||
this.doc.set('name', '');
|
||||
}
|
||||
|
||||
if (this.defaultValues) {
|
||||
for (let fieldname in this.defaultValues) {
|
||||
const value = this.defaultValues[fieldname];
|
||||
this.doc.set(fieldname, value);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
this.notFound = true;
|
||||
}
|
||||
this.setLinks();
|
||||
this.doc.on('change', this.setLinks);
|
||||
},
|
||||
async save() {
|
||||
this.setValidity();
|
||||
if (this.isFormInvalid) return;
|
||||
@ -132,8 +135,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.form-container {
|
||||
|
||||
}
|
||||
</style>
|
||||
|
@ -13,23 +13,24 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import frappe from 'frappejs';
|
||||
import ListRow from './ListRow';
|
||||
import ListCell from './ListCell';
|
||||
|
||||
export default {
|
||||
name: 'List',
|
||||
props: ['doctype'],
|
||||
watch: {
|
||||
doctype(oldValue, newValue) {
|
||||
if (oldValue !== newValue) {
|
||||
this.setupColumnsAndData();
|
||||
}
|
||||
}
|
||||
},
|
||||
props: ['listConfig'],
|
||||
components: {
|
||||
ListRow,
|
||||
ListCell
|
||||
},
|
||||
watch: {
|
||||
listConfig(oldValue, newValue) {
|
||||
if (oldValue.doctype !== newValue.doctype) {
|
||||
this.setupColumnsAndData();
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columns: [],
|
||||
@ -42,6 +43,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
setupColumnsAndData() {
|
||||
this.doctype = this.listConfig.doctype;
|
||||
this.meta = frappe.getMeta(this.doctype);
|
||||
|
||||
this.prepareColumns();
|
||||
this.updateData();
|
||||
},
|
||||
@ -49,11 +53,10 @@ export default {
|
||||
this.$router.push(`/edit/${this.doctype}/${name}`);
|
||||
},
|
||||
async updateData(keywords) {
|
||||
let filters = null;
|
||||
let filters = this.listConfig.filters || null;
|
||||
if (keywords) {
|
||||
filters = {
|
||||
keywords: ['like', keywords]
|
||||
}
|
||||
if (!filters) filters = {};
|
||||
filters.keywords = ['like', keywords];
|
||||
}
|
||||
this.data = await frappe.db.getAll({
|
||||
doctype: this.doctype,
|
||||
@ -62,7 +65,7 @@ export default {
|
||||
});
|
||||
},
|
||||
prepareColumns() {
|
||||
this.columns = this.meta.listView.columns.map(col => {
|
||||
this.columns = this.listConfig.columns.map(col => {
|
||||
if (typeof col === 'string') {
|
||||
const field = this.meta.getField(col);
|
||||
if (!field) return null;
|
||||
@ -77,11 +80,6 @@ export default {
|
||||
return col;
|
||||
}).filter(Boolean);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
meta() {
|
||||
return frappe.getMeta(this.doctype);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<search-input class="mr-2" @change="keyword => filterList(keyword)"/>
|
||||
</div>
|
||||
<div class="col-6 d-flex flex-row-reverse">
|
||||
<f-button primary @click="$emit('newClick')">{{ _('New {0}', doctype) }}</f-button>
|
||||
<f-button primary @click="$emit('newClick')">{{ _('New {0}', listConfig.title) }}</f-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -13,7 +13,7 @@ import SearchInput from '@/components/SearchInput';
|
||||
|
||||
export default {
|
||||
name: 'ListToolbar',
|
||||
props: ['doctype'],
|
||||
props: ['listConfig'],
|
||||
components: {
|
||||
SearchInput
|
||||
},
|
||||
|
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="bg-light">
|
||||
<page-header :title="meta.label || meta.name" />
|
||||
<page-header :title="listConfig.title" />
|
||||
<div class="px-4 py-3">
|
||||
<list-toolbar
|
||||
:doctype="doctype"
|
||||
:listConfig="listConfig"
|
||||
@newClick="openNewForm"
|
||||
@filterList="keyword => filterList(keyword)"
|
||||
class="mb-4"
|
||||
/>
|
||||
<list
|
||||
:doctype="doctype"
|
||||
:listConfig="listConfig"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -20,27 +20,35 @@ import Observable from 'frappejs/utils/observable';
|
||||
import PageHeader from '@/components/PageHeader';
|
||||
import ListToolbar from './ListToolbar';
|
||||
import List from './List';
|
||||
import listConfigs from './listConfig';
|
||||
|
||||
export default {
|
||||
name: 'ListView',
|
||||
props: ['doctype'],
|
||||
props: ['listName'],
|
||||
components: {
|
||||
PageHeader,
|
||||
ListToolbar,
|
||||
List
|
||||
},
|
||||
computed: {
|
||||
meta() {
|
||||
return frappe.getMeta(this.doctype);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
frappe.listView = new Observable();
|
||||
},
|
||||
methods: {
|
||||
async openNewForm() {
|
||||
const doc = await frappe.getNewDoc(this.doctype);
|
||||
this.$router.push(`/edit/${this.doctype}/${doc.name}`);
|
||||
const doctype = this.listConfig.doctype;
|
||||
const doc = await frappe.getNewDoc(doctype);
|
||||
if (this.listConfig.filters) {
|
||||
doc.set(this.listConfig.filters);
|
||||
}
|
||||
this.$router.push(`/edit/${doctype}/${doc.name}`);
|
||||
doc.on('afterInsert', () => {
|
||||
this.$router.push(`/edit/${doctype}/${doc.name}`);
|
||||
});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
listConfig() {
|
||||
return listConfigs[this.listName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
src/pages/ListView/listConfig.js
Normal file
9
src/pages/ListView/listConfig.js
Normal file
@ -0,0 +1,9 @@
|
||||
import Invoice from '../../../models/doctype/Invoice/InvoiceList';
|
||||
import Customer from '../../../models/doctype/Party/CustomerList';
|
||||
import Item from '../../../models/doctype/Item/ItemList';
|
||||
|
||||
export default {
|
||||
Invoice,
|
||||
Customer,
|
||||
Item
|
||||
}
|
@ -14,7 +14,7 @@ Vue.use(Router);
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/list/:doctype',
|
||||
path: '/list/:listName',
|
||||
name: 'ListView',
|
||||
component: ListView,
|
||||
props: true
|
||||
|
@ -1,5 +1,6 @@
|
||||
@import "variables.scss";
|
||||
@import "~bootstrap/scss/bootstrap";
|
||||
@import "~frappe-datatable/dist/frappe-datatable.css";
|
||||
|
||||
html {
|
||||
font-size: 14px;
|
||||
|
Loading…
Reference in New Issue
Block a user