| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- <template>
- <div>
- <DefaultHeaderPage title="Tesouraria" :show-filter-icon="false" />
- <div class="row items-center justify-between q-px-md q-mb-sm">
- <div class="text-subtitle1 text-weight-medium">Bancos / Caixa</div>
- <q-btn
- v-if="canAdd"
- color="primary"
- label="Nova conta"
- icon="mdi-plus"
- unelevated
- no-caps
- @click="openAccountCreate"
- />
- </div>
- <div class="row q-px-md q-col-gutter-md">
- <div
- v-for="acc in accounts"
- :key="acc.id"
- class="col-12 col-sm-6 col-md-4"
- >
- <q-card
- flat
- bordered
- class="q-pa-md cursor-pointer"
- :class="{ 'selected-card': acc.id === selectedId }"
- @click="selectAccount(acc)"
- >
- <div class="row items-center no-wrap">
- <q-icon name="mdi-bank-outline" size="sm" color="primary" class="q-mr-sm" />
- <div class="text-subtitle2 ellipsis">{{ acc.name }}</div>
- <q-space />
- <q-btn
- v-if="canEdit"
- flat
- round
- dense
- icon="mdi-pencil-outline"
- size="sm"
- @click.stop="openAccountEdit(acc)"
- />
- </div>
- <div class="text-h6 q-mt-sm">{{ formatCurrency(acc.balance) }}</div>
- <div class="text-caption text-grey-7">
- {{ acc.bank_name || "Conta" }}
- <span v-if="acc.bank_agency"> · Ag. {{ acc.bank_agency }}</span>
- <span v-if="acc.bank_account"> · CC {{ acc.bank_account }}</span>
- </div>
- </q-card>
- </div>
- <div v-if="!accounts.length" class="col-12 text-grey-7 q-pa-md">
- Nenhuma conta cadastrada. Clique em "Nova conta" para começar.
- </div>
- </div>
- <!-- Extrato -->
- <div v-if="selectedId" class="q-px-md q-mt-lg">
- <div class="row items-center justify-between q-mb-sm">
- <div class="text-subtitle1 text-weight-medium">
- Extrato — {{ selectedAccount?.name }}
- </div>
- </div>
- <DefaultTable
- v-model:rows="launches"
- no-api-call
- :add-item="canAdd"
- title="Movimentações"
- description="movimentações"
- :female="true"
- :columns="launchColumns"
- @on-add-item="openLaunchCreate"
- >
- <template #body-cell-transaction_type="{ row }">
- <q-td class="text-left">
- <q-chip
- :color="row.transaction_type === 'entrada' ? 'positive' : 'negative'"
- text-color="white"
- dense
- square
- :label="row.transaction_type === 'entrada' ? 'Entrada' : 'Saída'"
- />
- </q-td>
- </template>
- <template #body-cell-amount="{ row }">
- <q-td
- class="text-left text-weight-medium"
- :class="row.transaction_type === 'entrada' ? 'text-positive' : 'text-negative'"
- >
- {{ row.transaction_type === "entrada" ? "+" : "-" }}
- {{ formatCurrency(row.amount) }}
- </q-td>
- </template>
- <template #body-cell-actions="{ row }">
- <q-td>
- <div class="row no-wrap q-gutter-xs">
- <q-btn v-if="canEdit" outline icon="mdi-pencil-outline" style="width: 36px" @click.stop="openLaunchEdit(row)" />
- <q-btn v-if="canDelete" outline color="negative" icon="mdi-trash-can-outline" style="width: 36px" @click.stop="deleteLaunch(row)" />
- </div>
- </q-td>
- </template>
- </DefaultTable>
- </div>
- </div>
- </template>
- <script setup>
- import { computed, defineAsyncComponent, onMounted, ref } from "vue";
- import { useQuasar } from "quasar";
- import {
- getTreasuryAccountsMe,
- getTreasuryLaunchesMe,
- deleteTreasuryLaunchMe,
- } from "src/api/treasury";
- import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
- import DefaultTable from "src/components/defaults/DefaultTable.vue";
- import { permissionStore } from "src/stores/permission";
- const AddEditTreasuryAccountDialog = defineAsyncComponent(
- () => import("src/pages/financial/components/AddEditTreasuryAccountDialog.vue"),
- );
- const AddTreasuryLaunchDialog = defineAsyncComponent(
- () => import("src/pages/financial/components/AddTreasuryLaunchDialog.vue"),
- );
- const accounts = ref([]);
- const launches = ref([]);
- const selectedId = ref(null);
- const $q = useQuasar();
- const permissions = permissionStore();
- const canAdd = computed(() =>
- permissions.getAccess("franchisee_financial", "add"),
- );
- const canEdit = computed(() =>
- permissions.getAccess("franchisee_financial", "edit"),
- );
- const canDelete = computed(() =>
- permissions.getAccess("franchisee_financial", "delete"),
- );
- const launchColumns = [
- { name: "launch_date", label: "Data", field: "launch_date", align: "left" },
- { name: "description", label: "Descrição", field: "description", align: "left" },
- { name: "transaction_type", label: "Tipo", field: "transaction_type", align: "left" },
- { name: "amount", label: "Valor", field: "amount", align: "left" },
- { name: "actions", label: "Ações", field: null, align: "center" },
- ];
- const selectedAccount = computed(() =>
- accounts.value.find((a) => a.id === selectedId.value),
- );
- function formatCurrency(value) {
- return new Intl.NumberFormat("pt-BR", {
- style: "currency",
- currency: "BRL",
- }).format(Number(value ?? 0));
- }
- async function loadAccounts() {
- try {
- accounts.value = await getTreasuryAccountsMe();
- if (!selectedId.value && accounts.value.length) {
- selectAccount(accounts.value[0]);
- }
- } catch (e) {
- console.error("Erro ao carregar contas:", e);
- }
- }
- async function loadLaunches() {
- if (!selectedId.value) return;
- try {
- launches.value = await getTreasuryLaunchesMe(selectedId.value);
- } catch (e) {
- console.error("Erro ao carregar extrato:", e);
- }
- }
- function selectAccount(acc) {
- selectedId.value = acc.id;
- loadLaunches();
- }
- function openAccountCreate() {
- $q.dialog({
- component: AddEditTreasuryAccountDialog,
- }).onOk(loadAccounts);
- }
- function openAccountEdit(acc) {
- $q.dialog({
- component: AddEditTreasuryAccountDialog,
- componentProps: {
- account: acc,
- },
- }).onOk(loadAccounts);
- }
- function openLaunchCreate() {
- $q.dialog({
- component: AddTreasuryLaunchDialog,
- componentProps: {
- accountId: selectedId.value,
- },
- }).onOk(async () => {
- await loadAccounts();
- await loadLaunches();
- });
- }
- function openLaunchEdit(launch) {
- $q.dialog({
- component: AddTreasuryLaunchDialog,
- componentProps: { accountId: selectedId.value, launch },
- }).onOk(async () => {
- await Promise.all([loadAccounts(), loadLaunches()]);
- });
- }
- function deleteLaunch(launch) {
- $q.dialog({
- title: "Excluir movimentação",
- message: `Deseja excluir a movimentação "${launch.description}"?`,
- ok: { color: "negative", label: "Excluir" },
- cancel: { color: "secondary", outline: true, label: "Cancelar" },
- }).onOk(async () => {
- await deleteTreasuryLaunchMe(launch.id);
- await Promise.all([loadAccounts(), loadLaunches()]);
- });
- }
- onMounted(loadAccounts);
- </script>
- <style scoped>
- .selected-card {
- border-color: var(--q-primary);
- border-width: 2px;
- }
- </style>
|