|
|
@@ -0,0 +1,212 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <DefaultHeaderPage title="Plano de Contas" :show-filter-icon="false" />
|
|
|
+
|
|
|
+ <div class="row justify-end items-center q-px-md q-mb-sm">
|
|
|
+ <q-btn
|
|
|
+ color="primary"
|
|
|
+ label="Nova conta"
|
|
|
+ icon="mdi-plus"
|
|
|
+ unelevated
|
|
|
+ no-caps
|
|
|
+ @click="openCreate"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="q-px-md">
|
|
|
+ <DefaultTable
|
|
|
+ v-model:rows="rows"
|
|
|
+ no-api-call
|
|
|
+ :add-item="false"
|
|
|
+ title="Plano de Contas"
|
|
|
+ descricao="contas"
|
|
|
+ :feminino="true"
|
|
|
+ :columns="columns"
|
|
|
+ :delete-function="onDelete"
|
|
|
+ >
|
|
|
+ <template #body-cell-chart_type="{ row }">
|
|
|
+ <q-td class="text-left">
|
|
|
+ <q-chip
|
|
|
+ :color="row.chart_type === 'receita' ? 'positive' : 'blue-grey-5'"
|
|
|
+ text-color="white"
|
|
|
+ dense
|
|
|
+ square
|
|
|
+ :label="chartTypeLabel(row.chart_type)"
|
|
|
+ />
|
|
|
+ </q-td>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template #body-cell-actions="{ row }">
|
|
|
+ <q-td auto-width>
|
|
|
+ <q-btn
|
|
|
+ color="primary-2"
|
|
|
+ label="Editar"
|
|
|
+ dense
|
|
|
+ no-caps
|
|
|
+ outline
|
|
|
+ class="q-px-sm"
|
|
|
+ @click="openEdit(row)"
|
|
|
+ />
|
|
|
+ </q-td>
|
|
|
+ </template>
|
|
|
+ </DefaultTable>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <q-dialog v-model="dialog">
|
|
|
+ <q-card style="min-width: 360px; max-width: 460px">
|
|
|
+ <DefaultDialogHeader
|
|
|
+ :title="editing ? 'Editar conta' : 'Nova conta'"
|
|
|
+ @close="dialog = false"
|
|
|
+ />
|
|
|
+
|
|
|
+ <q-form ref="formRef">
|
|
|
+ <q-card-section class="q-gutter-sm">
|
|
|
+ <div class="row q-col-gutter-sm">
|
|
|
+ <DefaultInput
|
|
|
+ v-model="form.code"
|
|
|
+ label="Código (ex.: 1.1.01)"
|
|
|
+ class="col-5"
|
|
|
+ outlined
|
|
|
+ :rules="[(v) => !!v || 'Informe o código']"
|
|
|
+ />
|
|
|
+ <DefaultSelect
|
|
|
+ v-model="form.chart_type"
|
|
|
+ label="Tipo"
|
|
|
+ :options="chartTypeOptions"
|
|
|
+ class="col-7"
|
|
|
+ outlined
|
|
|
+ emit-value
|
|
|
+ map-options
|
|
|
+ :rules="[(v) => !!v || 'Selecione o tipo']"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <DefaultInput
|
|
|
+ v-model="form.description"
|
|
|
+ label="Descrição"
|
|
|
+ outlined
|
|
|
+ :rules="[(v) => !!v || 'Informe a descrição']"
|
|
|
+ />
|
|
|
+ </q-card-section>
|
|
|
+
|
|
|
+ <q-card-actions align="right" class="q-pa-md">
|
|
|
+ <q-btn flat label="Cancelar" color="grey-7" @click="dialog = false" />
|
|
|
+ <q-btn
|
|
|
+ color="primary"
|
|
|
+ label="Salvar"
|
|
|
+ :loading="saving"
|
|
|
+ @click="onSave"
|
|
|
+ />
|
|
|
+ </q-card-actions>
|
|
|
+ </q-form>
|
|
|
+ </q-card>
|
|
|
+ </q-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { onMounted, ref } from "vue";
|
|
|
+import { useQuasar } from "quasar";
|
|
|
+import {
|
|
|
+ getPlanAccountsMe,
|
|
|
+ createPlanAccountMe,
|
|
|
+ updatePlanAccountMe,
|
|
|
+ deletePlanAccountMe,
|
|
|
+} from "src/api/financial_plan_account";
|
|
|
+
|
|
|
+import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
|
|
|
+import DefaultTable from "src/components/defaults/DefaultTable.vue";
|
|
|
+import DefaultInput from "src/components/defaults/DefaultInput.vue";
|
|
|
+import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
|
|
|
+import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
|
|
|
+
|
|
|
+const $q = useQuasar();
|
|
|
+
|
|
|
+const rows = ref([]);
|
|
|
+const dialog = ref(false);
|
|
|
+const saving = ref(false);
|
|
|
+const editing = ref(false);
|
|
|
+const editingId = ref(null);
|
|
|
+const formRef = ref(null);
|
|
|
+
|
|
|
+const defaultForm = () => ({ code: "", description: "", chart_type: "despesa" });
|
|
|
+const form = ref(defaultForm());
|
|
|
+
|
|
|
+const chartTypeOptions = [
|
|
|
+ { label: "Receita", value: "receita" },
|
|
|
+ { label: "Despesa", value: "despesa" },
|
|
|
+];
|
|
|
+
|
|
|
+function chartTypeLabel(type) {
|
|
|
+ return chartTypeOptions.find((o) => o.value === type)?.label ?? type;
|
|
|
+}
|
|
|
+
|
|
|
+const columns = [
|
|
|
+ { name: "code", label: "Código", field: "code", align: "left", sortable: true },
|
|
|
+ { name: "description", label: "Descrição", field: "description", align: "left" },
|
|
|
+ { name: "chart_type", label: "Tipo", field: "chart_type", align: "left" },
|
|
|
+ { name: "actions", label: "Ações", field: "actions", align: "right" },
|
|
|
+];
|
|
|
+
|
|
|
+async function loadData() {
|
|
|
+ try {
|
|
|
+ rows.value = await getPlanAccountsMe();
|
|
|
+ } catch (e) {
|
|
|
+ console.error("Erro ao carregar plano de contas:", e);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function openCreate() {
|
|
|
+ editing.value = false;
|
|
|
+ editingId.value = null;
|
|
|
+ form.value = defaultForm();
|
|
|
+ dialog.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+function openEdit(row) {
|
|
|
+ editing.value = true;
|
|
|
+ editingId.value = row.id;
|
|
|
+ form.value = {
|
|
|
+ code: row.code,
|
|
|
+ description: row.description,
|
|
|
+ chart_type: row.chart_type,
|
|
|
+ };
|
|
|
+ dialog.value = true;
|
|
|
+}
|
|
|
+
|
|
|
+async function onSave() {
|
|
|
+ const valid = await formRef.value?.validate();
|
|
|
+ if (!valid) return;
|
|
|
+ saving.value = true;
|
|
|
+ try {
|
|
|
+ if (editing.value) {
|
|
|
+ await updatePlanAccountMe(editingId.value, form.value);
|
|
|
+ } else {
|
|
|
+ await createPlanAccountMe(form.value);
|
|
|
+ }
|
|
|
+ dialog.value = false;
|
|
|
+ await loadData();
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e);
|
|
|
+ } finally {
|
|
|
+ saving.value = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function onDelete(id) {
|
|
|
+ $q.dialog({
|
|
|
+ title: "Excluir conta",
|
|
|
+ message: "Tem certeza que deseja excluir esta conta do plano?",
|
|
|
+ cancel: true,
|
|
|
+ persistent: true,
|
|
|
+ }).onOk(async () => {
|
|
|
+ try {
|
|
|
+ await deletePlanAccountMe(id);
|
|
|
+ await loadData();
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(loadData);
|
|
|
+</script>
|