|
|
@@ -41,6 +41,7 @@
|
|
|
:key="card.label"
|
|
|
:caption="card.caption"
|
|
|
:label="card.label"
|
|
|
+ :nowrap-caption="card.nowrapCaption"
|
|
|
:value="card.value"
|
|
|
variant="primary"
|
|
|
/>
|
|
|
@@ -56,23 +57,39 @@
|
|
|
:key="card.label"
|
|
|
:caption="card.caption"
|
|
|
:label="card.label"
|
|
|
+ :nowrap-caption="card.nowrapCaption"
|
|
|
:value="card.value"
|
|
|
variant="secondary"
|
|
|
/>
|
|
|
</div>
|
|
|
|
|
|
- <q-card flat class="panel-card panel-card--soft expenses-panel">
|
|
|
- <div class="panel-title">Despesas do Período</div>
|
|
|
-
|
|
|
- <DashboardPayoutTable
|
|
|
- :columns="expenseTableColumns"
|
|
|
- empty-label="Nenhuma despesa encontrada para o período."
|
|
|
- row-key="key"
|
|
|
- :rows="expenseTableRows"
|
|
|
- total-label="Total de despesas"
|
|
|
- :total-row="expenseTableTotalRow"
|
|
|
- />
|
|
|
- </q-card>
|
|
|
+ <div class="expenses-grid">
|
|
|
+ <q-card flat class="panel-card panel-card--soft expenses-panel">
|
|
|
+ <div class="panel-title">Despesas do Período</div>
|
|
|
+
|
|
|
+ <DashboardPayoutTable
|
|
|
+ :columns="expenseTableColumns"
|
|
|
+ empty-label="Nenhuma despesa encontrada para o período."
|
|
|
+ row-key="key"
|
|
|
+ :rows="expenseTableRows"
|
|
|
+ total-label="Total de despesas"
|
|
|
+ :total-row="expenseTableTotalRow"
|
|
|
+ />
|
|
|
+ </q-card>
|
|
|
+
|
|
|
+ <q-card flat class="panel-card panel-card--soft expenses-panel">
|
|
|
+ <div class="panel-title">Manutenções do Período</div>
|
|
|
+
|
|
|
+ <DashboardPayoutTable
|
|
|
+ :columns="expenseTableColumns"
|
|
|
+ empty-label="Nenhuma manutenção encontrada para o período."
|
|
|
+ row-key="key"
|
|
|
+ :rows="maintenanceTableRows"
|
|
|
+ total-label="Total de manutenções"
|
|
|
+ :total-row="maintenanceTableTotalRow"
|
|
|
+ />
|
|
|
+ </q-card>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<q-inner-loading :showing="loading">
|
|
|
@@ -137,11 +154,15 @@ const defaultSummary = Object.freeze({
|
|
|
cleaning_total_amount: 0,
|
|
|
management_fee_amount: 0,
|
|
|
expenses_amount: 0,
|
|
|
+ manual_expenses_amount: 0,
|
|
|
payout_amount: 0,
|
|
|
expenses_breakdown: {
|
|
|
items: [],
|
|
|
+ system_expenses: [],
|
|
|
totals: {
|
|
|
expenses_amount: 0,
|
|
|
+ manual_expenses_amount: 0,
|
|
|
+ system_expenses_amount: 0,
|
|
|
},
|
|
|
},
|
|
|
});
|
|
|
@@ -260,14 +281,34 @@ const firstRowCards = computed(() => allMetricCards.value.slice(0, 7));
|
|
|
|
|
|
const secondRowCards = computed(() => allMetricCards.value.slice(7, 14));
|
|
|
|
|
|
-const expenseRows = computed(
|
|
|
- () => summary.value?.expenses_breakdown?.items ?? [],
|
|
|
+const manualExpenseRows = computed(
|
|
|
+ () =>
|
|
|
+ summary.value?.expenses_breakdown?.items?.filter(
|
|
|
+ (expense) => expense.source === "manual",
|
|
|
+ ) ?? [],
|
|
|
+);
|
|
|
+
|
|
|
+const resolveExpenseType = (expense) => expense.type ?? expense.category;
|
|
|
+
|
|
|
+const expenseRows = computed(() =>
|
|
|
+ manualExpenseRows.value.filter(
|
|
|
+ (expense) => resolveExpenseType(expense) === "expense",
|
|
|
+ ),
|
|
|
);
|
|
|
|
|
|
-const expenseTotal = computed(
|
|
|
- () => summary.value?.expenses_breakdown?.totals?.expenses_amount ?? 0,
|
|
|
+const maintenanceRows = computed(() =>
|
|
|
+ manualExpenseRows.value.filter(
|
|
|
+ (expense) => resolveExpenseType(expense) === "maintenance",
|
|
|
+ ),
|
|
|
);
|
|
|
|
|
|
+const sumExpenseRows = (rows) =>
|
|
|
+ rows.reduce((total, expense) => total + Number(expense.final_amount ?? 0), 0);
|
|
|
+
|
|
|
+const expenseTotal = computed(() => sumExpenseRows(expenseRows.value));
|
|
|
+
|
|
|
+const maintenanceTotal = computed(() => sumExpenseRows(maintenanceRows.value));
|
|
|
+
|
|
|
const expenseTableColumns = [
|
|
|
{
|
|
|
key: "label",
|
|
|
@@ -297,11 +338,24 @@ const expenseTableRows = computed(() =>
|
|
|
})),
|
|
|
);
|
|
|
|
|
|
+const maintenanceTableRows = computed(() =>
|
|
|
+ maintenanceRows.value.map((expense, index) => ({
|
|
|
+ ...expense,
|
|
|
+ key: expense.key || `${expense.label}-${index}`,
|
|
|
+ source_label: expense.source === "manual" ? "Interna" : "Stays/Sistema",
|
|
|
+ })),
|
|
|
+);
|
|
|
+
|
|
|
const expenseTableTotalRow = computed(() => ({
|
|
|
source_label: "",
|
|
|
final_amount: expenseTotal.value,
|
|
|
}));
|
|
|
|
|
|
+const maintenanceTableTotalRow = computed(() => ({
|
|
|
+ source_label: "",
|
|
|
+ final_amount: maintenanceTotal.value,
|
|
|
+}));
|
|
|
+
|
|
|
const buildDashboardParams = ({ year, month, propertyId } = {}) => {
|
|
|
const params = {};
|
|
|
|
|
|
@@ -510,9 +564,21 @@ onMounted(async () => {
|
|
|
background: #f0f3f5;
|
|
|
}
|
|
|
|
|
|
-.expenses-panel {
|
|
|
- width: 50%;
|
|
|
- align-self: flex-start;
|
|
|
+.expenses-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
+ gap: 16px;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.expenses-panel :deep(.payout-table th),
|
|
|
+.expenses-panel :deep(.payout-table td),
|
|
|
+.expenses-panel :deep(.payout-total-row td) {
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+
|
|
|
+.expenses-panel :deep(.header-wrapper) {
|
|
|
+ align-items: flex-start;
|
|
|
}
|
|
|
|
|
|
.panel-title {
|
|
|
@@ -557,8 +623,8 @@ onMounted(async () => {
|
|
|
gap: 10px;
|
|
|
}
|
|
|
|
|
|
- .expenses-panel {
|
|
|
- width: 100%;
|
|
|
+ .expenses-grid {
|
|
|
+ grid-template-columns: 1fr;
|
|
|
}
|
|
|
}
|
|
|
</style>
|