update ux

add pager
This commit is contained in:
Simon Vieille 2024-09-18 15:18:16 +02:00
commit 0de1c5dc2f
10 changed files with 130 additions and 46 deletions

View file

@ -3,7 +3,7 @@
<div class="d-flex justify-content-between p-3 mb-3">
<h3>Comptes bancaires</h3>
<BButtonToolbar key-nav>
<BButton @click="doAdd">Ajouter</BButton>
<BButton variant="primary" @click="doAdd">Ajouter</BButton>
</BButtonToolbar>
</div>
<BTableSimple caption-top responsive v-if="data !== null">

View file

@ -3,7 +3,7 @@
<div class="d-flex justify-content-between p-3 mb-3">
<h3>Catégories</h3>
<BButtonToolbar key-nav>
<BButton @click="doAdd">Ajouter</BButton>
<BButton variant="primary" @click="doAdd">Ajouter</BButton>
</BButtonToolbar>
</div>
<BTableSimple caption-top responsive v-if="data !== null">

View file

@ -1,31 +1,42 @@
<template>
<BContainer fluid class="p-0">
<div class="d-flex justify-content-between p-3 mb-3">
<h3>Transactions</h3>
<div class="d-flex justify-content-between p-3">
<h3 class="mb-0">Transactions</h3>
<div v-if="data !== null" class="d-flex justify-content-between gap-2">
<BPagination v-model="page" :per-page="limit" :total-rows="limit*pages" @page-click="updatePage" class="m-0" />
<BFormSelect
v-model="limit"
:options="limits"
@change="updateLimit"
:required="true"
/>
</div>
<BButtonToolbar key-nav>
<BButton @click="doAdd">Importer</BButton>
<BButton variant="primary" @click="doAdd">Importer</BButton>
</BButtonToolbar>
</div>
<BTableSimple caption-top responsive v-if="data !== null">
<BThead>
<BTr>
<BTh v-for="field in fields" :width="field.width" class="cursor" :class="field.classes" @click="doSort(field.key)">
<SortButton :currentOrder="order" :currentSort="sort" :order="field.key" :label="field.label" />
</BTh>
</Btr>
</BThead>
<BTbody>
<BTr v-for="row in data.rows">
<BTd v-for="field in fields">
<span v-if="field.key">
<span v-if="field.render" v-html="field.render(row)"></span>
<span v-else v-text="row[field.key]"></span>
</span>
<span v-else="field.render" v-html="field.render(row)"></span>
</BTd>
</Btr>
</BTbody>
</BTableSimple>
<div class="crud-list">
<BTableSimple caption-top v-if="data !== null">
<BThead>
<BTr>
<BTh v-for="field in fields" :width="field.width" class="cursor" :class="field.thClasses" @click="doSort(field.key)">
<SortButton :currentOrder="order" :currentSort="sort" :order="field.key" :label="field.label" />
</BTh>
</Btr>
</BThead>
<BTbody>
<BTr v-for="row in data.rows">
<BTd v-for="field in fields" :width="field.width" :class="field.tdClasses">
<span v-if="field.key">
<span v-if="field.render" v-html="field.render(row)"></span>
<span v-else v-text="row[field.key]"></span>
</span>
<span v-else="field.render" v-html="field.render(row)"></span>
</BTd>
</Btr>
</BTbody>
</BTableSimple>
</div>
<BModal v-if="form !== null" v-model="formShow" :title="form?.label" @ok="doSave">
<BAlert :model-value="form.error !== null" variant="danger" v-text="form.error"></BAlert>
<BForm @submit="doSave">
@ -90,6 +101,7 @@ import {
BButtonToolbar,
BFormSelect,
BFormFile,
BPagination,
} from 'bootstrap-vue-next'
import SortButton from './../components/SortButton.vue'
@ -100,11 +112,33 @@ const order = ref(null)
const sort = ref(null)
const page = ref(1)
const pages = ref(null)
const limit = ref(null)
const limit = ref(10)
const form = ref(null)
const formShow = ref(false)
const endpoint = `/api/transaction`
const defineLimits = () => {
let v = []
for (let i of [10, 20, 50, 100]) {
v.push({value: i, text: i})
}
return v
}
const limits = defineLimits()
const updatePage = (event, value) => {
page.value = value
refresh()
}
const updateLimit = () => {
page.value = 1
refresh()
}
const refresh = () => {
fetch(`${endpoint}?${new URLSearchParams({
order: order.value,
@ -238,37 +272,53 @@ const fields = [
{
key: 'date',
label: 'Date',
width: '90px',
render: (item) => renderDate(item.date),
},
{
key: 'accounted_at',
label: 'Comptabilisé',
render: (item) => renderDate(item.accounted_at),
},
{
key: 'short_label',
label: 'Libelle simplifie',
},
{
key: 'label',
label: 'Libelle',
},
{
key: 'information',
label: 'Informations',
width: '150px',
label: 'Libellé',
},
{
key: 'operation_type',
width: '120px',
label: 'Type',
},
{
key: 'debit',
label: 'Débit',
width: '120px',
thClasses: ['text-end'],
tdClasses: ['text-end'],
},
{
key: 'credit',
label: 'Crédit',
width: '120px',
thClasses: ['text-end'],
tdClasses: ['text-end'],
},
{
key: 'category',
label: 'Catégorie',
width: '120px',
render: (item) => {
if (item.category !== null) {
return item.category.label
}
},
},
{
key: 'bank_account',
label: 'Compte',
width: '120px',
render: (item) => {
if (item.bank_account !== null) {
return item.bank_account.label
}
},
}
]
onMounted(() => {

View file

@ -3,7 +3,7 @@
<div class="d-flex justify-content-between p-3 mb-3">
<h3>Utilisateurs</h3>
<BButtonToolbar key-nav>
<BButton @click="doAdd">Ajouter</BButton>
<BButton variant="primary" @click="doAdd">Ajouter</BButton>
</BButtonToolbar>
</div>
<BTableSimple caption-top responsive v-if="data !== null">

View file

@ -17,6 +17,7 @@
#app, main {
min-height: 100vh;
max-height: 100vh;
overflow: hidden;
}
$nav-size: 300px;
@ -25,6 +26,22 @@ $nav-size: 300px;
width: $nav-size;
}
.crud {
&-list {
width: calc(100vw - $nav-size);
height: calc(100vh - 90px);
overflow: auto;
thead th {
position: sticky;
top: 0;
z-index: 1;
}
}
}
#body {
width: calc(100vw - $nav-size);
max-height: 100vh;
overflow: scroll;
}

View file

@ -16,7 +16,6 @@ func (ctrl *Controller) Config() crud.Configuration {
Model: model.BankAccount{},
Models: []model.BankAccount{},
ValidOrders: []string{"id", "label"},
ValidLimits: []int{20, 50, 100},
DefaultLimit: 20,
CreateModel: func() interface{} {
return new(model.BankAccount)

View file

@ -16,8 +16,7 @@ func (ctrl *Controller) Config() crud.Configuration {
Model: model.Category{},
Models: []model.Category{},
ValidOrders: []string{"id", "label"},
ValidLimits: []int{20, 50, 100},
DefaultLimit: 20,
DefaultLimit: 100,
CreateModel: func() interface{} {
return new(model.Category)
},

View file

@ -1,5 +1,7 @@
package crud
import "gorm.io/gorm"
type Configuration struct {
Model interface{}
Models any
@ -9,6 +11,7 @@ type Configuration struct {
DefaultSort string
DefaultLimit int
CreateModel func() interface{}
ListQuery func(*gorm.DB)
}
func (c *Configuration) GetDefaultOrder() string {
@ -27,6 +30,14 @@ func (c *Configuration) GetDefaultSort() string {
return "asc"
}
func (c *Configuration) GetValidLimits() []int {
if len(c.ValidLimits) > 0 {
return c.ValidLimits
}
return []int{10, 20, 50, 100}
}
func (c *Configuration) IsValidOrder(value string) bool {
for _, v := range c.ValidOrders {
if v == value {
@ -38,7 +49,7 @@ func (c *Configuration) IsValidOrder(value string) bool {
}
func (c *Configuration) IsValidLimit(value int) bool {
for _, v := range c.ValidLimits {
for _, v := range c.GetValidLimits() {
if v == value {
return true
}

View file

@ -50,6 +50,10 @@ func (ctrl *Controller) List(c echo.Context) error {
Desc: sort == "desc",
})
if ctrl.Config.ListQuery != nil {
ctrl.Config.ListQuery(db)
}
data := ListData{
Limit: ctrl.Config.DefaultLimit,
Order: order,

View file

@ -10,6 +10,7 @@ import (
"gitnet.fr/deblan/budget/database/manager"
"gitnet.fr/deblan/budget/database/model"
"gitnet.fr/deblan/budget/web/controller/crud"
"gorm.io/gorm"
)
type Controller struct {
@ -21,13 +22,16 @@ func (ctrl *Controller) Config() crud.Configuration {
Model: model.Transaction{},
Models: []model.Transaction{},
ValidOrders: []string{"accounted_at", "short_label", "label", "reference", "information", "operation_type", "debit", "credit", "date"},
ValidLimits: []int{20, 50, 100},
DefaultLimit: 20,
DefaultOrder: "date",
DefaultSort: "desc",
CreateModel: func() interface{} {
return new(model.Transaction)
},
ListQuery: func(db *gorm.DB) {
db.Joins("BankAccount")
db.Joins("Category")
},
}
}