| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- <template>
- <q-table
- v-model:fullscreen="fullscreen"
- flat
- :class="
- props.table
- ? 'softpar-table bg-background table-bottom'
- : 'softpar-table bg-background '
- "
- :pagination="{ rowsPerPage }"
- :pagination-label="getPaginationLabel"
- row-key="id"
- :rows="rows"
- :rows-per-page-label="props.rowsPerPageLabel"
- :columns="props.columns"
- :visible-columns="visibleColumns"
- :filter="filter"
- @row-click="onRowClick"
- >
- <template #top>
- <q-input
- v-if="mostrarCampoPesquisa"
- v-model="filter"
- outlined
- dense
- debounce="500"
- placeholder="Buscar"
- style="min-width: 400px"
- clearable
- autofocus
- >
- <template #append>
- <q-icon name="mdi-magnify" />
- </template>
- </q-input>
- <q-checkbox
- v-if="props.mostrarToggleInativos"
- v-model="showInativos"
- class="q-ml-sm"
- :label="props.labelInativo"
- dense
- color="secondary"
- />
- <q-select
- v-if="mostrarSelecaoDeColunas"
- v-model="visibleColumns"
- class="q-ml-md"
- multiple
- dense
- outlined
- options-outlined
- :display-value="$q.lang.table.columns"
- emit-value
- map-options
- :options="mapColuns"
- option-value="name"
- style="min-width: 150px"
- options-selected-class="text-bold"
- />
- <q-btn
- v-if="mostrarBotaoFullscreen"
- flat
- class="q-ml-md"
- @click="fullscreen = !fullscreen"
- >
- <q-icon name="mdi-fullscreen" />
- </q-btn>
- <q-space />
- <q-btn-dropdown
- v-if="props.dropDown"
- class="q-mr-md"
- color="primary"
- label="opcoes"
- />
- <q-btn
- v-if="props.addItem"
- class="button-secondary"
- color="primary"
- padding="12px 16px"
- :outline="props.outlineAdd"
- :label="props.labelAdd"
- @click="onAddItem"
- >
- </q-btn>
- </template>
- <template #body-cell-status="{ value, row }">
- <q-td style="width: 8%">
- <q-item-section>
- <span class="text-center">
- <div v-if="row.status && value" class="ativo body2 text-positive">
- {{ $t("active") }}
- </div>
- <div v-if="!row.status" class="inativo body2 text-accent">
- {{ $t("inactive") }}
- </div>
- </span>
- </q-item-section>
- </q-td>
- </template>
- <template #body-cell-ativo="{ value, row }">
- <q-td style="width: 8%">
- <q-item-section>
- <span class="text-center">
- <div v-if="row.ativo && value" class="ativo body2 text-positive">
- {{ $t("active") }}
- </div>
- <div v-if="row.ativo && !value" class="ativo body2 text-positive">
- {{ $t("active") }}
- </div>
- <div v-if="!row.ativo" class="inativo body2 text-accent">
- {{ $t("active") }}
- </div>
- </span>
- </q-item-section>
- </q-td>
- </template>
- <template #body-cell-principal="{ value, row }">
- <q-td style="width: 1%">
- <q-item-section>
- <span class="text-center">
- <q-icon
- v-if="row.principal && value"
- name="mdi-star"
- size="1.5rem"
- style="color: #385873"
- onmouseover="this.style.color='#688FAF';"
- onmouseout="this.style.color='#385873';"
- @click.stop="togglePrincipal(row)"
- />
- <q-icon
- v-if="!row.principal"
- name="mdi-star-outline"
- size="1.5rem"
- style="color: #385873"
- onmouseover="this.style.color='#688FAF';"
- onmouseout="this.style.color='#385873';"
- @click.stop="togglePrincipal(row)"
- />
- </span>
- </q-item-section>
- </q-td>
- </template>
- <template v-if="!props.hideNoDataLabel" #no-data>
- <div class="q-my-md row justify-center full-width">
- <q-spinner v-if="loading" color="primary" size="30px" />
- <div v-else class="q-pa-md body2">{{ $t("no_records_found") }}</div>
- </div>
- </template>
- <template v-for="(index, name) in $slots" #[name]="data">
- <slot :name="name" v-bind="data"></slot>
- </template>
- </q-table>
- </template>
- <script setup>
- import { ref, onMounted, toRaw, watch } from "vue";
- import { useRouter } from "vue-router";
- import { api } from "boot/axios";
- const emit = defineEmits([
- "onRowClick",
- "onAddItem",
- "noRows",
- "togglePrincipal",
- ]);
- const props = defineProps({
- // colunas de configuração da tabela
- columns: {
- type: Array,
- required: true,
- },
- // rota da api, ex: /clientes
- apiRoute: {
- type: String,
- required: true,
- },
- labelAdd: {
- type: String,
- default: "Adicionar",
- },
- // botao de adicionar com aparencia de outline
- outlineAdd: {
- type: Boolean,
- default: false,
- },
- // ir para sub pagina on row click
- openItem: {
- type: Boolean,
- default: false,
- },
- // rota da sub page
- openItemRoute: {
- type: String,
- default: "",
- },
- // botao de adicionar
- addItem: {
- type: Boolean,
- default: true,
- },
- // botao de opcoes
- dropDown: {
- type: Boolean,
- default: false,
- },
- // botao de adicionar route
- addItemRoute: {
- type: String,
- default: "",
- },
- // quantidade de items por pagina
- rowsPerPage: {
- type: Number,
- default: 10,
- },
- comecarDesativado: {
- type: Boolean,
- default: false,
- },
- mostrarSelecaoDeColunas: {
- type: Boolean,
- default: false,
- },
- mostrarBotaoFullscreen: {
- type: Boolean,
- default: false,
- },
- mostrarToggleInativos: {
- type: Boolean,
- default: false,
- },
- mostrarCampoPesquisa: {
- type: Boolean,
- default: true,
- },
- noApiRoute: {
- type: Boolean,
- default: false,
- },
- table: {
- type: Boolean,
- default: false,
- },
- rowsPerPageLabel: {
- type: String,
- default: "Linhas por página",
- },
- hideNoDataLabel: {
- type: Boolean,
- default: false,
- },
- labelInativo: {
- type: String,
- default: "Exibir inativos",
- },
- });
- const router = useRouter();
- const rows = ref([]);
- const filter = ref("");
- const loading = ref(true);
- const fullscreen = ref(false);
- const showInativos = ref(false);
- const inativos = ref([]);
- const getPaginationLabel = (from, to, last) => {
- return `${from}-${to} de ${last}`;
- };
- watch(showInativos, () => {
- if (showInativos.value) {
- rows.value = rows.value.concat(inativos.value);
- } else {
- inativos.value = rows.value.filter(
- (row) => row.status === false || row.ativo === false,
- );
- rows.value = rows.value.filter((row) => row.ativo);
- }
- });
- watch(
- () => props.apiRoute,
- () => {
- onRequest();
- },
- );
- // remove as colunas obrigatórias do filtro de colunas
- const mapColuns = props.columns.reduce((accm, column) => {
- if (!column.required) {
- column.label = column.label.toUpperCase();
- accm.push(column);
- }
- return accm;
- }, []);
- // as colunas que serão carregadas
- const visibleColumns = ref(mapColuns.map((column) => column.name));
- const onRowClick = (evt, row, index) => {
- const item = toRaw(row);
- if (props.openItem) {
- if (props.openItemRoute) {
- router.push({ name: props.openItemRoute, params: { id: item.id } });
- } else {
- emit("onRowClick", { evt, row, index });
- }
- }
- };
- const onAddItem = () => {
- if (props.addItem) {
- if (props.addItemRoute) {
- router.push({ name: props.addItemRoute });
- } else {
- emit("onAddItem");
- }
- }
- };
- // busca os dados do banco com filtros e pagination
- const onRequest = async () => {
- // const filter = params.filter;
- if (props.noApiRoute) {
- loading.value = false;
- return;
- }
- // inicia o loading
- loading.value = true;
- // pega os dados do servidor
- const response = await api.get(`${props.apiRoute}`);
- // limpa os dados atuais e adiciona os novos
- rows.value.splice(0, rows.value.length, ...response.data.result);
- if (props.mostrarToggleInativos && !showInativos.value) {
- inativos.value = rows.value.filter(
- (row) => row.status === false || row.ativo === false,
- );
- rows.value = rows.value.filter((row) => row.ativo || row.status === true);
- }
- if (rows.value.length == 0) {
- emit("noRows");
- }
- // finaliza o loading
- loading.value = false;
- };
- // funcao exclusiva para contatos table, para alterar o contato principal
- const togglePrincipal = async (row) => {
- emit("togglePrincipal", row);
- };
- onMounted(() => {
- // faz a primeira requisição
- onRequest({
- filter: undefined,
- });
- if (props.comecarDesativado) {
- visibleColumns.value = mapColuns
- .map((column) => column.required)
- .map((column) => column.name);
- }
- });
- </script>
- <style lang="scss">
- @import "src/css/table.scss";
- .ativo {
- justify-content: center;
- align-items: center;
- padding: 5px 12px;
- gap: 10px;
- background: #cfdab7;
- border-radius: 24px;
- }
- .chip {
- justify-content: center;
- align-items: center;
- padding: 5px 12px;
- gap: 10px;
- border-radius: 24px;
- }
- .inativo {
- justify-content: center;
- align-items: flex-start;
- padding: 5px 12px;
- gap: 10px;
- background: #f7cfbb;
- border-radius: 24px;
- }
- </style>
|