| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- <template>
- <div>
- <DefaultHeaderPage>
- <template #after>
- <q-btn
- unelevated
- class="btn-export"
- :label="$t('relatorio.exportar_excel')"
- icon="mdi-download"
- padding="8px 16px"
- :loading="exportLoading"
- @click="onExport"
- />
- </template>
- </DefaultHeaderPage>
- <div class="relatorio-tabs-row q-mb-md">
- <div
- v-for="tab in tabs"
- :key="tab.name"
- class="relatorio-tab-card"
- :class="{ active: activeTab === tab.name }"
- @click="selectTab(tab.name)"
- >
- <q-icon :name="tab.icon" size="22px" color="violet-normal" />
- <div class="tab-body">
- <span class="tab-count">
- {{ counters[tab.counterKey] !== undefined ? counters[tab.counterKey] : '—' }}
- </span>
- <span class="tab-label">{{ tab.label }}</span>
- </div>
- </div>
- </div>
- <div v-if="activeTab === 'novos-associados'">
- <DefaultTableServerSide
- :key="tableKey"
- :columns="columnsNovosAssociados"
- :api-call="getNovoAssociadosPaginated"
- :add-item="false"
- :show-search-field="true"
- />
- </div>
- <div v-else-if="activeTab === 'contatos-associados'">
- <DefaultTableServerSide
- :key="tableKey"
- :columns="columnsContatos"
- :api-call="getContatosAssociadosPaginated"
- :add-item="false"
- :show-search-field="true"
- />
- </div>
- <div v-else-if="activeTab === 'exclusoes-mes'">
- <DefaultTableServerSide
- :key="tableKey"
- :columns="columnsExclusoes"
- :api-call="getExclusoesMesPaginated"
- :add-item="false"
- :show-search-field="true"
- />
- </div>
- </div>
- </template>
- <script setup>
- import { ref, onMounted } from "vue";
- import { useQuasar } from "quasar";
- import { useI18n } from "vue-i18n";
- import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
- import DefaultTableServerSide from "src/components/defaults/DefaultTableServerSide.vue";
- import {
- getRelatorioCounters,
- getNovoAssociadosPaginated,
- getContatosAssociadosPaginated,
- getExclusoesMesPaginated,
- exportRelatorio,
- } from "src/api/relatorio.js";
- const $q = useQuasar();
- const { t } = useI18n();
- const activeTab = ref("novos-associados");
- const tableKey = ref(0);
- const exportLoading = ref(false);
- const counters = ref({
- novos_associados: undefined,
- contatos: undefined,
- exclusoes_mes: undefined,
- });
- const tabs = [
- {
- name: "novos-associados",
- label: t("relatorio.novos_associados"),
- icon: "mdi-account-multiple-outline",
- counterKey: "novos_associados",
- },
- {
- name: "contatos-associados",
- label: t("relatorio.contatos"),
- icon: "mdi-phone-outline",
- counterKey: "contatos",
- },
- {
- name: "exclusoes-mes",
- label: t("relatorio.exclusoes_mes"),
- icon: "mdi-account-remove-outline",
- counterKey: "exclusoes_mes",
- },
- ];
- const columnsNovosAssociados = [
- {
- name: "name",
- label: t("common.terms.name"),
- field: "name",
- align: "left",
- sortable: true,
- },
- {
- name: "cpf",
- label: t("associado.cpf"),
- field: "cpf",
- align: "left",
- sortable: false,
- },
- {
- name: "created_at",
- label: t("relatorio.col.cadastro"),
- field: "created_at",
- align: "left",
- sortable: false,
- },
- ];
- const columnsContatos = [
- {
- name: "name",
- label: t("common.terms.name"),
- field: "name",
- align: "left",
- sortable: true,
- },
- {
- name: "phone",
- label: t("associado.phone"),
- field: "phone",
- align: "left",
- sortable: false,
- },
- {
- name: "email",
- label: t("associado.email"),
- field: "email",
- align: "left",
- sortable: false,
- },
- ];
- const columnsExclusoes = [
- {
- name: "name",
- label: t("common.terms.name"),
- field: "name",
- align: "left",
- sortable: true,
- },
- {
- name: "cpf",
- label: t("associado.cpf"),
- field: "cpf",
- align: "left",
- sortable: false,
- },
- {
- name: "excluded_at",
- label: t("relatorio.col.exclusao"),
- field: "excluded_at",
- align: "left",
- sortable: false,
- },
- ];
- const selectTab = (name) => {
- activeTab.value = name;
- tableKey.value++;
- };
- const onExport = async () => {
- exportLoading.value = true;
- try {
- await exportRelatorio(activeTab.value);
- } catch {
- $q.notify({ type: "negative", message: t("http.errors.failed") });
- } finally {
- exportLoading.value = false;
- }
- };
- onMounted(async () => {
- try {
- const data = await getRelatorioCounters();
- counters.value = data;
- } catch {
- // counters permanecem como undefined, exibindo '—'
- }
- });
- </script>
- <style lang="scss" scoped>
- @use "src/css/quasar.variables.scss" as vars;
- .relatorio-tabs-row {
- display: flex;
- gap: 12px;
- }
- .relatorio-tab-card {
- flex: 1;
- display: flex;
- align-items: center;
- gap: 12px;
- padding: 14px 20px;
- border-radius: 8px;
- border: 1.5px solid vars.$color-border;
- background: vars.$surface;
- cursor: pointer;
- transition: border-color 0.15s, background 0.15s;
- user-select: none;
- &:hover:not(.active) {
- border-color: vars.$violet-light-active;
- background: vars.$violet-light;
- }
- &.active {
- border-color: vars.$violet-normal;
- background: vars.$violet-light;
- }
- }
- .tab-body {
- display: flex;
- align-items: baseline;
- gap: 8px;
- }
- .tab-count {
- font-size: 1.375rem;
- font-weight: 700;
- color: vars.$violet-normal;
- line-height: 1;
- }
- .tab-label {
- font-size: 0.875rem;
- color: vars.$color-text-2;
- font-weight: 400;
- }
- .btn-export {
- background: linear-gradient(90deg, #4d1658 0%, #8b30a5 100%) !important;
- color: white !important;
- border-radius: 8px !important;
- }
- .btn-export :deep(.q-icon) {
- color: white !important;
- }
- </style>
|