| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- <template>
- <q-table
- v-model:fullscreen="fullscreen"
- flat
- :pagination="{ rowsPerPage }"
- :pagination-label="getPaginationLabel"
- row-key="id"
- :rows="rows"
- :rows-per-page-label="$t('common.ui.table.rows_per_page')"
- :columns="columns"
- :visible-columns="visibleColumns"
- :filter="filter"
- :grid="$q.screen.lt.sm"
- :loading="loading"
- class="softpar-table q-pa-sm"
- @row-click="onRowClick"
- >
- <template #top>
- <div
- class="flex full-width justify-between align-center q-mb-md q-pl-sm"
- style="gap: 1rem"
- >
- <q-input
- v-if="showSearchField"
- v-model="filter"
- debounce="250"
- :placeholder="$t('common.actions.search')"
- clearable
- autofocus
- class=""
- color="primary"
- >
- <template #append>
- <q-icon name="mdi-magnify" />
- </template>
- </q-input>
- <q-select
- v-if="showColumnsSelect"
- v-model="visibleColumns"
- multiple
- options-outlined
- :display-value="$q.lang.table.columns"
- emit-value
- map-options
- :options="mapColumns"
- style="width: 150px"
- options-selected-class="text-bold"
- />
- <q-space />
- <q-btn
- v-if="addItem"
- color="primary"
- padding="10px 16px"
- :outline="outlineAdd"
- :label="$t('common.actions.add')"
- @click="onAddItem"
- >
- </q-btn>
- </div>
- </template>
- <template #body-cell-actions="{ row }">
- <q-td v-if="deleteFunction">
- <q-item-section>
- <q-btn
- color="negative"
- flat
- dense
- icon="mdi-delete"
- style="width: 45px"
- class="q-ml-auto q-mr-sm"
- @click.prevent.stop="onDelete(row.id)"
- />
- </q-item-section>
- </q-td>
- </template>
- <template #loading>
- <q-inner-loading showing color="primary" />
- </template>
- <template v-if="!hideNoDataLabel" #no-data>
- <div v-if="!loading" class="q-my-md row justify-center full-width">
- <div class="q-pa-md body2">
- {{ $t("http.errors.no_records_found") }}
- </div>
- </div>
- </template>
- <template v-for="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";
- const emit = defineEmits(["onRowClick", "onAddItem", "noRows"]);
- const {
- columns,
- apiCall,
- outlineAdd,
- openItem,
- openItemRoute,
- addItem,
- addItemRoute,
- rowsPerPage,
- showSearchField,
- noApiCall,
- hideNoDataLabel,
- deleteFunction,
- } = defineProps({
- columns: {
- type: Array,
- required: true,
- },
- apiCall: {
- type: Function,
- required: true,
- },
- outlineAdd: {
- type: Boolean,
- default: false,
- },
- openItem: {
- type: Boolean,
- default: false,
- },
- openItemRoute: {
- type: String,
- default: "",
- },
- addItem: {
- type: Boolean,
- default: true,
- },
- addItemRoute: {
- type: String,
- default: "",
- },
- rowsPerPage: {
- type: Number,
- default: 10,
- },
- showSearchField: {
- type: Boolean,
- default: true,
- },
- showColumnsSelect: {
- type: Boolean,
- default: true,
- },
- noApiCall: {
- type: Boolean,
- default: false,
- },
- hideNoDataLabel: {
- type: Boolean,
- default: false,
- },
- deleteFunction: {
- type: Function,
- default: null,
- },
- });
- 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(
- () => apiCall,
- async () => {
- await onRequest();
- },
- );
- const mapColumns = columns.reduce((accm, column) => {
- if (!column.required) {
- accm.push({
- label: column.label,
- value: column.name,
- });
- }
- return accm;
- }, []);
- const visibleColumns = ref(mapColumns.map((column) => column.value));
- const onRowClick = (evt, row, index) => {
- const item = toRaw(row);
- if (openItem) {
- if (openItemRoute) {
- router.push({ name: openItemRoute, params: { id: item.id } });
- } else {
- emit("onRowClick", { evt, row, index });
- }
- }
- };
- const onAddItem = () => {
- if (addItem) {
- if (addItemRoute) {
- router.push({ name: addItemRoute });
- } else {
- emit("onAddItem");
- }
- }
- };
- const onDelete = async (id) => {
- if (deleteFunction) {
- loading.value = true;
- try {
- await deleteFunction(id);
- await onRequest();
- } catch (error) {
- console.error(error);
- } finally {
- loading.value = false;
- }
- }
- };
- const onRequest = async () => {
- if (noApiCall) {
- loading.value = false;
- return;
- }
- loading.value = true;
- const response = await apiCall();
- rows.value.splice(0, rows.value.length, ...response);
- if (rows.value.length == 0) {
- emit("noRows");
- }
- loading.value = false;
- };
- onMounted(async () => {
- await onRequest({
- filter: undefined,
- });
- });
- defineExpose({
- refresh: onRequest,
- });
- </script>
- <style lang="scss">
- @import "src/css/table.scss";
- </style>
|