@freteclick/quasar-financial-ui 1.0.113 → 1.0.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,117 +1,208 @@
1
1
  <template>
2
- <div>
3
- <div class="col-xs-12 q-mb-md">
4
- <div class="row justify-end">
5
- <q-btn
6
- label="Adicionar despesa"
7
- icon="add"
8
- size="md"
9
- color="primary"
10
- class="q-ml-sm"
11
- @click="dialogs.expense.visible = true"
12
- />
13
- </div>
14
- </div>
15
- <Filters :filters="filters" @onRequest="onRequest" />
16
- <q-table
17
- flat
18
- :loading="isLoading"
19
- :rows="data"
20
- :columns="settings.columns"
21
- v-model:pagination="pagination"
22
- @request="onRequest"
23
- row-key="id"
24
- style="min-height: 90vh"
25
- :rows-per-page-options="[5, 10, 15, 20, 25, 50]"
26
- >
27
- <template v-slot:body="props">
28
- <q-tr :props="props">
29
- <q-td key="id" :props="props">
30
- <q-btn
31
- outline
32
- dense
33
- :to="{ name: 'PayDetails', params: { id: props.row.id } }"
34
- :label="props.cols[0].value"
35
- :style="{ color: props.row.color_status }"
36
- class="full-width"
37
- />
38
- </q-td>
39
- <q-td key="tipo" :props="props">{{ props.cols[1].value }}</q-td>
40
- <q-td key="description" :props="props">
41
- {{ props.row.description }}
42
- </q-td>
43
- <q-td key="dataVencimento" :props="props">{{
44
- props.cols[3].value
45
- }}</q-td>
46
- <q-td key="categoria" :props="props">{{ props.cols[4].value }}</q-td>
47
- <q-td key="fornecedor" :props="props">{{ props.cols[5].value }}</q-td>
48
- <q-td
49
- key="status"
50
- :props="props"
51
- :style="{ color: props.row.color_status }"
52
- >
53
- {{ $t(`invoice.statuses.${props.row.status}`) }}
54
- </q-td>
55
- <q-td key="preco" :props="props">{{ props.cols[7].value }}</q-td>
56
- </q-tr>
57
- </template>
58
- </q-table>
59
-
60
- <q-dialog
61
- v-model="dialogs.orders.visible"
62
- transition-show="scale"
63
- transition-hide="scale"
64
- >
65
- <q-card
66
- class="text-white"
67
- style="background-color: #00519b; width: 300px"
2
+ <div class="payable-invoices">
3
+ <FilterBox title="Filtros">
4
+ <Filters
5
+ :filters="filters"
6
+ variant="filter-box"
7
+ :show-category="true"
8
+ @onRequest="onFilterRequest"
9
+ />
10
+ </FilterBox>
11
+
12
+ <section class="payable-invoices__panel">
13
+ <header class="payable-invoices__heading">
14
+ <div>
15
+ <span class="payable-invoices__eyebrow">DESPESAS</span>
16
+ <h2>Faturas de pagamento</h2>
17
+ <p>Acompanhe vencimentos e valores das contas da sua empresa.</p>
18
+ </div>
19
+ <q-card flat class="payable-total-card">
20
+ <div class="payable-total-card__icon">
21
+ <q-icon name="payments" />
22
+ </div>
23
+ <div class="payable-total-card__copy">
24
+ <span>Valor total a pagar</span>
25
+ <strong>{{ filteredTotalAmount }}</strong>
26
+ <small>Soma de todas as faturas filtradas</small>
27
+ </div>
28
+ </q-card>
29
+ </header>
30
+
31
+ <q-table
32
+ flat
33
+ class="payable-invoices__table"
34
+ :loading="isLoading"
35
+ :rows="data"
36
+ :columns="settings.columns"
37
+ v-model:pagination="pagination"
38
+ @request="onRequest"
39
+ row-key="id"
40
+ :rows-per-page-options="[10, 25, 50]"
41
+ :grid="$q.screen.lt.sm"
42
+ no-data-label="Nenhuma fatura encontrada"
43
+ no-results-label="Nenhuma fatura corresponde aos filtros"
44
+ loading-label="Carregando despesas..."
45
+ rows-per-page-label="Linhas por página"
68
46
  >
69
- <q-card-section>
70
- <div class="row items-center">
71
- <div class="text-h6">
72
- {{ $t("finance.orders") }} da Fatura #{{ dialogs.orders.invoice }}
73
- </div>
74
- <q-space />
75
- <q-btn icon="close" color="white" flat round dense v-close-popup />
47
+ <template v-slot:body="props">
48
+ <q-tr :props="props" class="payable-invoices__row">
49
+ <q-td key="id" :props="props">
50
+ <q-btn
51
+ flat
52
+ dense
53
+ no-caps
54
+ icon="receipt_long"
55
+ :label="`#${props.row.id}`"
56
+ :to="{ name: 'PayDetails', params: { id: props.row.id } }"
57
+ class="payable-invoice-link"
58
+ />
59
+ </q-td>
60
+ <q-td key="tipo" :props="props">
61
+ <q-badge class="payable-type-badge">{{ props.row.tipo }}</q-badge>
62
+ </q-td>
63
+ <q-td key="description" :props="props" class="payable-description-cell">
64
+ {{ props.row.description }}
65
+ </q-td>
66
+ <q-td key="dataVencimento" :props="props">
67
+ <div class="payable-date-cell">
68
+ <q-icon name="event" />
69
+ <span>{{ props.row.dataVencimentoLabel }}</span>
70
+ </div>
71
+ </q-td>
72
+ <q-td key="categoria" :props="props">{{ props.row.categoryName }}</q-td>
73
+ <q-td key="fornecedor" :props="props">{{ props.row.fornecedor }}</q-td>
74
+ <q-td key="status" :props="props">
75
+ <q-badge
76
+ rounded
77
+ class="payable-status-badge"
78
+ :style="statusStyle(props.row.color_status)"
79
+ >
80
+ <span class="payable-status-badge__dot" />
81
+ {{ statusLabel(props.row.status) }}
82
+ </q-badge>
83
+ </q-td>
84
+ <q-td key="preco" :props="props" class="payable-price-cell">
85
+ {{ props.cols[7].value }}
86
+ </q-td>
87
+ </q-tr>
88
+ </template>
89
+
90
+ <template v-slot:item="props">
91
+ <div class="col-12">
92
+ <q-card flat bordered class="payable-mobile-card">
93
+ <div class="payable-mobile-card__top">
94
+ <q-btn
95
+ flat
96
+ dense
97
+ no-caps
98
+ icon="receipt_long"
99
+ :label="`#${props.row.id}`"
100
+ :to="{ name: 'PayDetails', params: { id: props.row.id } }"
101
+ class="payable-invoice-link"
102
+ />
103
+ <q-badge
104
+ rounded
105
+ class="payable-status-badge"
106
+ :style="statusStyle(props.row.color_status)"
107
+ >
108
+ <span class="payable-status-badge__dot" />
109
+ {{ statusLabel(props.row.status) }}
110
+ </q-badge>
111
+ </div>
112
+ <div class="payable-mobile-card__type">{{ props.row.tipo }}</div>
113
+ <p class="payable-mobile-card__description">{{ props.row.description }}</p>
114
+ <div class="payable-mobile-card__grid">
115
+ <div>
116
+ <span>Vencimento</span>
117
+ <strong>{{ props.row.dataVencimentoLabel }}</strong>
118
+ </div>
119
+ <div>
120
+ <span>Valor</span>
121
+ <strong>{{ props.cols[7].value }}</strong>
122
+ </div>
123
+ <div>
124
+ <span>Categoria</span>
125
+ <strong>{{ props.row.categoryName }}</strong>
126
+ </div>
127
+ <div>
128
+ <span>Fornecedor</span>
129
+ <strong>{{ props.row.fornecedor }}</strong>
130
+ </div>
131
+ </div>
132
+ <div class="payable-mobile-card__actions">
133
+ <q-btn
134
+ flat
135
+ dense
136
+ no-caps
137
+ icon="link"
138
+ color="primary"
139
+ :label="ordersLabel(props.row.pedidos)"
140
+ :disable="!props.row.pedidos.length"
141
+ @click="seeOrdersList(props.row.pedidos, props.row.id)"
142
+ />
143
+ <q-btn
144
+ unelevated
145
+ dense
146
+ no-caps
147
+ color="primary"
148
+ label="Abrir fatura"
149
+ :to="{ name: 'PayDetails', params: { id: props.row.id } }"
150
+ />
151
+ </div>
152
+ </q-card>
76
153
  </div>
154
+ </template>
155
+ </q-table>
156
+ </section>
157
+
158
+ <q-dialog v-model="dialogs.orders.visible" transition-show="scale" transition-hide="scale">
159
+ <q-card class="payable-orders-dialog">
160
+ <q-card-section class="payable-orders-dialog__header">
161
+ <div>
162
+ <span>DETALHES DA FATURA</span>
163
+ <h3>{{ $t("finance.orders") }} da fatura #{{ dialogs.orders.invoice }}</h3>
164
+ </div>
165
+ <q-btn icon="close" flat round dense v-close-popup aria-label="Fechar" />
77
166
  </q-card-section>
78
-
79
- <q-card-section class="q-pt-none">
80
- <q-markup-table>
81
- <tbody>
82
- <tr v-for="(orderId, index) in dialogs.orders.items" :key="index">
83
- <td class="text-center">
84
- <q-btn
85
- flat
86
- color="primary"
87
- :label="`Ver ${$t('finance.order')} #${orderId}`"
88
- :to="{
89
- name: 'PurchasingOrderDetails',
90
- params: {
91
- id: orderId,
92
- },
93
- }"
94
- />
95
- </td>
96
- </tr>
97
- </tbody>
98
- </q-markup-table>
99
- </q-card-section>
167
+ <div class="payable-orders-dialog__list">
168
+ <q-list separator>
169
+ <q-item v-for="(orderId, index) in dialogs.orders.items" :key="index">
170
+ <q-item-section avatar>
171
+ <q-avatar color="blue-1" text-color="primary" icon="receipt" />
172
+ </q-item-section>
173
+ <q-item-section>{{ $t("finance.order") }} #{{ orderId }}</q-item-section>
174
+ <q-item-section side>
175
+ <q-btn
176
+ flat
177
+ dense
178
+ no-caps
179
+ color="primary"
180
+ label="Abrir"
181
+ :to="{ name: 'PurchasingOrderDetails', params: { id: orderId } }"
182
+ />
183
+ </q-item-section>
184
+ </q-item>
185
+ </q-list>
186
+ </div>
100
187
  </q-card>
101
188
  </q-dialog>
102
189
 
103
190
  <q-dialog v-model="dialogs.expense.visible">
104
- <q-card style="width: 700px; max-width: 80vw">
105
- <q-card-section class="row items-center">
106
- <div class="text-h6">Nova despesa</div>
107
- <q-space />
108
- <q-btn icon="close" flat round dense v-close-popup />
191
+ <q-card class="payable-expense-dialog">
192
+ <q-card-section class="payable-expense-dialog__header">
193
+ <div>
194
+ <span>NOVA DESPESA</span>
195
+ <h3>Adicionar despesa</h3>
196
+ <p>Preencha os dados para registrar um pagamento ou despesa recorrente.</p>
197
+ </div>
198
+ <q-btn icon="close" flat round dense v-close-popup aria-label="Fechar" />
109
199
  </q-card-section>
110
- <q-card-section>
111
- <CreateExpense @created="onRequest({ pagination, filters })" />
200
+ <q-card-section class="payable-expense-dialog__body">
201
+ <CreateExpense @created="onExpenseCreated" />
112
202
  </q-card-section>
113
203
  </q-card>
114
204
  </q-dialog>
205
+
115
206
  </div>
116
207
  </template>
117
208
 
@@ -123,11 +214,13 @@ import {
123
214
  } from "@freteclick/quasar-common-ui/src/utils/formatter";
124
215
  import CreateExpense from "../expense/CreateExpense";
125
216
  import { date } from "quasar";
217
+ import FilterBox from "@freteclick/quasar-common-ui/src/components/common/FilterBox.vue";
126
218
  import Filters from "../../common/Filters.vue";
127
219
 
128
220
  export default {
129
221
  components: {
130
222
  CreateExpense,
223
+ FilterBox,
131
224
  Filters,
132
225
  },
133
226
 
@@ -167,18 +260,21 @@ export default {
167
260
  return `#${val}`;
168
261
  },
169
262
  label: "ID",
263
+ sortable: false,
170
264
  },
171
265
  {
172
266
  name: "tipo",
173
267
  align: "left",
174
268
  field: "tipo",
175
269
  label: "Tipo",
270
+ sortable: false,
176
271
  },
177
272
  {
178
273
  name: "description",
179
274
  align: "left",
180
275
  field: "description",
181
276
  label: this.$t("finance.description"),
277
+ sortable: false,
182
278
  },
183
279
  {
184
280
  name: "dataVencimento",
@@ -188,33 +284,38 @@ export default {
188
284
  return formatDateYmdTodmY(val);
189
285
  },
190
286
  label: "Data vencimento",
287
+ sortable: false,
191
288
  },
192
289
  {
193
290
  name: "categoria",
194
291
  field: "categoryName",
195
292
  align: "left",
196
293
  label: "Categoria",
294
+ sortable: false,
197
295
  },
198
296
  {
199
297
  name: "fornecedor",
200
298
  field: "fornecedor",
201
299
  align: "left",
202
300
  label: "Fornecedor",
301
+ sortable: false,
203
302
  },
204
303
  {
205
304
  name: "status",
206
305
  field: "status",
207
306
  align: "left",
208
307
  label: "Status",
308
+ sortable: false,
209
309
  },
210
310
  {
211
311
  name: "preco",
212
312
  field: "preco",
213
- align: "left",
313
+ align: "right",
214
314
  format: (val, row) => {
215
315
  return formatMoney(val, "BRL", "pt-br");
216
316
  },
217
317
  label: "Preço",
318
+ sortable: false,
218
319
  },
219
320
  ],
220
321
  }),
@@ -241,13 +342,14 @@ export default {
241
342
  },
242
343
  text: null,
243
344
  status: statuses[0],
345
+ category: { label: "Todas", value: null },
244
346
  company: null,
245
347
  },
246
348
  pagination: {
247
349
  sortBy: "dataVencimento",
248
- descending: false,
350
+ descending: true,
249
351
  page: 1,
250
- rowsPerPage: 25,
352
+ rowsPerPage: 10,
251
353
  rowsNumber: 10,
252
354
  },
253
355
  };
@@ -260,8 +362,15 @@ export default {
260
362
  violations: "payInvoice/violations",
261
363
  items: "payInvoice/items",
262
364
  totalItems: "payInvoice/totalItems",
365
+ totalAmount: "payInvoice/totalAmount",
263
366
  myCompany: "people/currentCompany",
264
367
  }),
368
+
369
+ filteredTotalAmount() {
370
+ if (this.totalAmount === null || this.totalAmount === undefined) return "—";
371
+
372
+ return formatMoney(Number(this.totalAmount) || 0, "BRL", "pt-br");
373
+ },
265
374
  },
266
375
 
267
376
  watch: {
@@ -282,36 +391,44 @@ export default {
282
391
  items(items) {
283
392
  if (!items) return;
284
393
 
285
- let data = [];
286
-
287
- for (let i in items) {
288
- let item = items[i];
289
- let orders = [];
290
-
291
- for (let o in item.order) {
292
- orders.push(
293
- item.order[o].order["@id"].match(
294
- /^\/purchasing\/orders\/([a-z0-9-]*)$/
295
- )[1]
296
- );
297
- }
298
-
299
- data.push({
300
- "@id": item["@id"],
301
- id: item["@id"].match(/^\/finance\/pay\/([a-z0-9-]*)$/)[1],
302
- tipo: this.$t(item.invoice_type),
394
+ this.data = items.map((item) => {
395
+ const orderEntries = Array.isArray(item.order) ? item.order : [];
396
+ const orders = orderEntries
397
+ .map((entry) => {
398
+ const orderUri = entry && entry.order && entry.order["@id"];
399
+ const match = String(orderUri || "").match(
400
+ /\/purchasing\/orders\/([a-z0-9-]+)$/i
401
+ );
402
+
403
+ return match ? match[1] : null;
404
+ })
405
+ .filter(Boolean);
406
+ const firstOrder =
407
+ (orderEntries.find((entry) => entry && entry.order) || {}).order || {};
408
+ const provider = firstOrder.provider || {};
409
+ const invoiceUri = String(item["@id"] || "");
410
+ const invoiceId = invoiceUri.match(/\/finance\/pay\/([a-z0-9-]+)$/i);
411
+
412
+ return {
413
+ "@id": invoiceUri,
414
+ id: (invoiceId && invoiceId[1]) || item.id,
415
+ tipo: item.invoice_type ? this.$t(item.invoice_type) : "—",
303
416
  pedidos: orders,
304
- description: item.description,
305
- color_status: item.status.color,
306
- dataVencimento: item.dueDate,
307
- fornecedor: `${item.order[0].order.provider.name} ${item.order[0].order.provider.alias}`,
308
- status: item.status.status,
309
- categoryName: item.categoryName,
310
- preco: item.price,
311
- });
312
- }
313
-
314
- this.data = data;
417
+ description: item.description || "—",
418
+ color_status: (item.status && item.status.color) || "",
419
+ dataVencimento: item.dueDate || "",
420
+ dataVencimentoLabel: item.dueDate
421
+ ? formatDateYmdTodmY(item.dueDate)
422
+ : "—",
423
+ fornecedor:
424
+ [provider.name, provider.alias]
425
+ .filter((value, index, values) => value && values.indexOf(value) === index)
426
+ .join(" · ") || "—",
427
+ status: (item.status && item.status.status) || "",
428
+ categoryName: item.categoryName || "—",
429
+ preco: item.price || 0,
430
+ };
431
+ });
315
432
  },
316
433
  },
317
434
 
@@ -337,23 +454,52 @@ export default {
337
454
  this.dialogs.orders.visible = true;
338
455
  },
339
456
 
457
+ ordersLabel(orders) {
458
+ const count = Array.isArray(orders) ? orders.length : 0;
459
+ return count === 1 ? "1 pedido" : `${count} pedidos`;
460
+ },
461
+
462
+ statusLabel(status) {
463
+ return status ? this.$t(`invoice.statuses.${status}`) : "—";
464
+ },
465
+
466
+ statusStyle(color) {
467
+ return color ? { color } : {};
468
+ },
469
+
470
+ openExpenseDialog() {
471
+ this.dialogs.expense.visible = true;
472
+ },
473
+
474
+ onExpenseCreated() {
475
+ this.dialogs.expense.visible = false;
476
+ this.pagination.page = 1;
477
+ this.onRequest({ pagination: this.pagination });
478
+ },
479
+
480
+ onFilterRequest() {
481
+ this.pagination.page = 1;
482
+ this.onRequest({ pagination: this.pagination });
483
+ },
484
+
340
485
  onRequest(props) {
341
486
  if (this.isLoading) return;
342
487
 
343
- let pagination = props ? props.pagination : this.pagination;
344
-
345
- let { page, rowsPerPage, sortBy, descending } = pagination;
488
+ const requestedPagination =
489
+ props && props.pagination ? props.pagination : this.pagination;
490
+ const page = Number(requestedPagination.page) || 1;
491
+ const rowsPerPage = Number(requestedPagination.rowsPerPage) || 10;
346
492
 
347
- let params = { itemsPerPage: rowsPerPage, page };
493
+ const params = { itemsPerPage: rowsPerPage, page };
348
494
 
349
495
  params.from = this.formatDate(this.filters.date.from) || "";
350
496
  params.to = this.formatDate(this.filters.date.to) || "";
351
- params.orderType = this.filters.orderType.value || "";
497
+ params.orderType = (this.filters.orderType && this.filters.orderType.value) || "";
352
498
 
353
499
  if (this.filters.text != null && this.filters.text.length > 0) {
354
500
  if (this.filters.text.length < 2) return;
355
501
 
356
- params["searchBy"] = this.filters.text;
502
+ params.searchBy = this.filters.text.trim();
357
503
  }
358
504
 
359
505
  if (this.filters.status != null) {
@@ -366,6 +512,10 @@ export default {
366
512
  }
367
513
  }
368
514
 
515
+ if (this.filters.category && this.filters.category.value) {
516
+ params.category = this.filters.category.value;
517
+ }
518
+
369
519
  if (this.filters.company != null) {
370
520
  params["myCompany"] = this.filters.company.id;
371
521
  }
@@ -374,15 +524,438 @@ export default {
374
524
  params["order.order"] = this.orderId;
375
525
  }
376
526
 
377
- params["invoice[dueDate]"] = "desc";
378
-
379
527
  this.getItems(params).then(() => {
380
- this.pagination.page = page;
381
- this.pagination.rowsPerPage = rowsPerPage;
382
- this.pagination.sortBy = sortBy;
383
- this.pagination.descending = descending;
528
+ this.pagination = {
529
+ ...this.pagination,
530
+ page,
531
+ rowsPerPage,
532
+ sortBy: "dataVencimento",
533
+ descending: true,
534
+ };
384
535
  });
385
536
  },
386
537
  },
387
538
  };
388
539
  </script>
540
+
541
+ <style lang="scss" scoped>
542
+ .payable-invoices {
543
+ display: grid;
544
+ width: 100%;
545
+ min-width: 0;
546
+ gap: 20px;
547
+ color: #1b2d43;
548
+ }
549
+
550
+ .payable-invoices__panel {
551
+ width: 100%;
552
+ min-width: 0;
553
+ box-sizing: border-box;
554
+ overflow: hidden;
555
+ border: 1px solid #e5ebf3;
556
+ border-radius: 19px;
557
+ background: #fff;
558
+ box-shadow: 0 12px 32px rgba(25, 48, 78, 0.05);
559
+ }
560
+
561
+ .payable-invoices__heading {
562
+ display: flex;
563
+ align-items: center;
564
+ justify-content: space-between;
565
+ gap: 22px;
566
+ padding: 22px 25px;
567
+ border-bottom: 1px solid #edf1f6;
568
+ }
569
+
570
+ .payable-invoices__eyebrow {
571
+ color: #7890aa;
572
+ font-size: 10px;
573
+ font-weight: 750;
574
+ letter-spacing: 0.13em;
575
+ }
576
+
577
+ .payable-invoices__heading h2 {
578
+ margin: 5px 0 0;
579
+ color: #1a2e45;
580
+ font-size: 19px;
581
+ font-weight: 720;
582
+ letter-spacing: -0.02em;
583
+ }
584
+
585
+ .payable-invoices__heading p {
586
+ margin: 5px 0 0;
587
+ color: #7b8b9c;
588
+ font-size: 12px;
589
+ }
590
+
591
+ .payable-total-card {
592
+ display: flex;
593
+ width: min(100%, 410px);
594
+ min-width: 280px;
595
+ align-items: center;
596
+ gap: 12px;
597
+ margin-left: auto;
598
+ padding: 12px 16px;
599
+ border: 1px solid #e7edf4;
600
+ border-radius: 14px;
601
+ background: #fbfdff;
602
+ }
603
+
604
+ .payable-total-card__icon {
605
+ display: grid;
606
+ width: 42px;
607
+ height: 42px;
608
+ flex: 0 0 auto;
609
+ place-items: center;
610
+ border-radius: 13px;
611
+ color: #27805a;
612
+ background: #e8f7ef;
613
+ font-size: 21px;
614
+ }
615
+
616
+ .payable-total-card__copy {
617
+ display: flex;
618
+ min-width: 0;
619
+ flex-direction: column;
620
+ }
621
+
622
+ .payable-total-card__copy > span {
623
+ color: #6f7f91;
624
+ font-size: 11px;
625
+ font-weight: 650;
626
+ }
627
+
628
+ .payable-total-card__copy strong {
629
+ overflow: hidden;
630
+ margin-top: 2px;
631
+ color: #1a2e45;
632
+ font-size: clamp(17px, 1.5vw, 22px);
633
+ font-weight: 750;
634
+ letter-spacing: -0.035em;
635
+ text-overflow: ellipsis;
636
+ white-space: nowrap;
637
+ }
638
+
639
+ .payable-total-card__copy small {
640
+ margin-top: 1px;
641
+ color: #93a0af;
642
+ font-size: 10px;
643
+ }
644
+
645
+ .payable-invoices__table {
646
+ width: 100%;
647
+ min-width: 0;
648
+ color: #33465b;
649
+ }
650
+
651
+ .payable-invoices__table :deep(.q-table thead tr) {
652
+ height: 48px;
653
+ background: #f8fafc;
654
+ }
655
+
656
+ .payable-invoices__table :deep(.q-table thead th) {
657
+ padding: 0 16px;
658
+ color: #7b8b9c;
659
+ font-size: 10px;
660
+ font-weight: 750;
661
+ letter-spacing: 0.07em;
662
+ text-transform: uppercase;
663
+ white-space: nowrap;
664
+ }
665
+
666
+ .payable-invoices__table :deep(.q-table tbody td) {
667
+ height: 64px;
668
+ padding: 10px 16px;
669
+ border-color: #edf1f5;
670
+ font-size: 12px;
671
+ white-space: nowrap;
672
+ }
673
+
674
+ .payable-invoices__table :deep(.q-table tbody tr) {
675
+ transition: background-color 0.15s ease;
676
+ }
677
+
678
+ .payable-invoices__table :deep(.q-table tbody tr:hover) {
679
+ background: #f8fbff;
680
+ }
681
+
682
+ .payable-invoices__table :deep(.q-table__bottom) {
683
+ min-height: 58px;
684
+ padding: 8px 18px;
685
+ border-top: 1px solid #edf1f5;
686
+ color: #718096;
687
+ font-size: 12px;
688
+ }
689
+
690
+ .payable-invoice-link {
691
+ border-radius: 8px;
692
+ color: #245d9c;
693
+ font-size: 12px;
694
+ font-weight: 750;
695
+ }
696
+
697
+ .payable-invoice-link :deep(.q-icon) {
698
+ font-size: 17px;
699
+ }
700
+
701
+ .payable-type-badge {
702
+ padding: 6px 9px;
703
+ border-radius: 7px;
704
+ color: #526b86;
705
+ background: #eef3f8;
706
+ font-size: 10px;
707
+ font-weight: 650;
708
+ }
709
+
710
+ .payable-description-cell {
711
+ max-width: 240px;
712
+ overflow: hidden;
713
+ text-overflow: ellipsis;
714
+ white-space: nowrap;
715
+ }
716
+
717
+ .payable-date-cell {
718
+ display: flex;
719
+ align-items: center;
720
+ gap: 7px;
721
+ white-space: nowrap;
722
+ }
723
+
724
+ .payable-date-cell .q-icon {
725
+ color: #8294a8;
726
+ font-size: 16px;
727
+ }
728
+
729
+ .payable-status-badge {
730
+ display: inline-flex;
731
+ align-items: center;
732
+ gap: 6px;
733
+ padding: 6px 9px;
734
+ border-radius: 20px;
735
+ background: #f0f4f7;
736
+ font-size: 10px;
737
+ font-weight: 700;
738
+ }
739
+
740
+ .payable-status-badge__dot {
741
+ width: 6px;
742
+ height: 6px;
743
+ border-radius: 50%;
744
+ background: currentColor;
745
+ }
746
+
747
+ .payable-price-cell {
748
+ color: #1e3e5e;
749
+ font-weight: 750;
750
+ white-space: nowrap;
751
+ }
752
+
753
+ .payable-mobile-card {
754
+ margin: 4px 0;
755
+ padding: 16px;
756
+ border-color: #e7edf4;
757
+ border-radius: 15px;
758
+ background: #fff;
759
+ }
760
+
761
+ .payable-mobile-card__top,
762
+ .payable-mobile-card__actions {
763
+ display: flex;
764
+ align-items: center;
765
+ justify-content: space-between;
766
+ gap: 10px;
767
+ }
768
+
769
+ .payable-mobile-card__type {
770
+ margin: 6px 0 0;
771
+ color: #728398;
772
+ font-size: 11px;
773
+ }
774
+
775
+ .payable-mobile-card__description {
776
+ margin: 8px 0 14px;
777
+ color: #33465b;
778
+ font-size: 13px;
779
+ font-weight: 600;
780
+ }
781
+
782
+ .payable-mobile-card__grid {
783
+ display: grid;
784
+ grid-template-columns: repeat(2, minmax(0, 1fr));
785
+ gap: 13px 10px;
786
+ }
787
+
788
+ .payable-mobile-card__grid > div {
789
+ display: flex;
790
+ min-width: 0;
791
+ flex-direction: column;
792
+ gap: 4px;
793
+ }
794
+
795
+ .payable-mobile-card__grid span {
796
+ color: #8795a5;
797
+ font-size: 10px;
798
+ }
799
+
800
+ .payable-mobile-card__grid strong {
801
+ overflow: hidden;
802
+ color: #263b52;
803
+ font-size: 12px;
804
+ font-weight: 650;
805
+ text-overflow: ellipsis;
806
+ white-space: nowrap;
807
+ }
808
+
809
+ .payable-mobile-card__actions {
810
+ margin-top: 16px;
811
+ padding-top: 12px;
812
+ border-top: 1px solid #edf1f5;
813
+ }
814
+
815
+ .payable-orders-dialog {
816
+ width: min(100%, 620px);
817
+ overflow: hidden;
818
+ border-radius: 18px;
819
+ }
820
+
821
+ .payable-orders-dialog {
822
+ display: flex;
823
+ width: min(100%, 520px);
824
+ max-height: min(82vh, 760px);
825
+ flex-direction: column;
826
+ }
827
+
828
+ .payable-orders-dialog__header,
829
+ .payable-expense-dialog__header {
830
+ display: flex;
831
+ align-items: center;
832
+ justify-content: space-between;
833
+ gap: 12px;
834
+ padding: 20px 22px;
835
+ border-bottom: 1px solid #edf1f6;
836
+ }
837
+
838
+ .payable-orders-dialog__header span,
839
+ .payable-expense-dialog__header span {
840
+ color: #7890aa;
841
+ font-size: 9px;
842
+ font-weight: 750;
843
+ letter-spacing: 0.12em;
844
+ }
845
+
846
+ .payable-orders-dialog__header h3,
847
+ .payable-expense-dialog__header h3 {
848
+ margin: 5px 0 0;
849
+ color: #1a2e45;
850
+ font-size: 17px;
851
+ font-weight: 700;
852
+ }
853
+
854
+ .payable-orders-dialog__list {
855
+ min-height: 0;
856
+ flex: 1 1 auto;
857
+ overflow-y: auto;
858
+ overscroll-behavior: contain;
859
+ }
860
+
861
+ .payable-expense-dialog__body {
862
+ min-height: 0;
863
+ flex: 1 1 auto;
864
+ overflow-y: auto;
865
+ padding: 22px 26px 26px;
866
+ }
867
+
868
+ .payable-expense-dialog {
869
+ display: flex;
870
+ width: min(100%, 780px);
871
+ max-height: min(92vh, 900px);
872
+ flex-direction: column;
873
+ overflow: hidden;
874
+ border-radius: 20px;
875
+ }
876
+
877
+ .payable-expense-dialog__header {
878
+ padding: 22px 26px 19px;
879
+ border-bottom: 0;
880
+ color: #fff;
881
+ background: linear-gradient(115deg, #15395d 0%, #1b568b 100%);
882
+ }
883
+
884
+ .payable-expense-dialog__header span {
885
+ color: #c3d8ee;
886
+ }
887
+
888
+ .payable-expense-dialog__header h3 {
889
+ color: #fff;
890
+ font-size: 21px;
891
+ }
892
+
893
+ .payable-expense-dialog__header p {
894
+ margin: 5px 0 0;
895
+ color: #d6e4f2;
896
+ font-size: 12px;
897
+ }
898
+
899
+ .payable-expense-dialog__header .q-btn {
900
+ color: #fff;
901
+ }
902
+
903
+ @media (min-width: 601px) {
904
+ .payable-invoices__table :deep(.q-table__container),
905
+ .payable-invoices__table :deep(.q-table__middle) {
906
+ width: 100%;
907
+ max-width: 100%;
908
+ min-width: 0;
909
+ }
910
+
911
+ .payable-invoices__table :deep(.q-table__middle) {
912
+ overflow-x: auto !important;
913
+ overflow-y: hidden;
914
+ overscroll-behavior-x: contain;
915
+ -webkit-overflow-scrolling: touch;
916
+ }
917
+
918
+ .payable-invoices__table :deep(.q-table__middle > table) {
919
+ min-width: 1280px;
920
+ }
921
+ }
922
+
923
+ @media (max-width: 900px) {
924
+ .payable-invoices__heading {
925
+ align-items: flex-start;
926
+ flex-direction: column;
927
+ }
928
+
929
+ .payable-total-card {
930
+ width: 100%;
931
+ min-width: 0;
932
+ margin-left: 0;
933
+ }
934
+ }
935
+
936
+ @media (max-width: 600px) {
937
+ .payable-invoices__heading {
938
+ gap: 14px;
939
+ padding: 18px 17px;
940
+ }
941
+
942
+ .payable-mobile-card__actions {
943
+ flex-wrap: wrap;
944
+ }
945
+
946
+ .payable-expense-dialog {
947
+ width: calc(100vw - 24px);
948
+ max-height: 92vh;
949
+ border-radius: 17px;
950
+ }
951
+
952
+ .payable-expense-dialog__header {
953
+ padding: 19px 18px 16px;
954
+ }
955
+
956
+ .payable-expense-dialog__body {
957
+ padding: 17px 18px 20px;
958
+ }
959
+
960
+ }
961
+ </style>