소스 검색

Merge branch 'feature/SERPRATI-JOY-868kf24hh-alteracoes-administrador' of Softpar/sfp_front_vue_serprati_digital into development

joycekepler 6 일 전
부모
커밋
ba461e2296

+ 19 - 4
src/api/user.js

@@ -54,11 +54,21 @@ export const getParceiros = async () => {
   return users.filter((u) => u.type === "parceiro");
 };
 
-export const getUsersPaginated = async ({ page = 1, perPage = 10, filter, type, status } = {}) => {
+export const getUsersPaginated = async ({
+  page = 1,
+  perPage = 10,
+  filter,
+  type,
+  status,
+  position_id,
+  sector_id,
+} = {}) => {
   const params = { page, per_page: perPage };
-  if (type)   params.type   = type;
-  if (status) params.status = status;
-  if (filter) params.search = filter;
+  if (type)        params.type        = type;
+  if (status)      params.status      = status;
+  if (filter)      params.search      = filter;
+  if (position_id) params.position_id = position_id;
+  if (sector_id)   params.sector_id   = sector_id;
   const { data } = await api.get("/user/paginated", { params });
   return { data: { result: data.payload } };
 };
@@ -71,6 +81,11 @@ export const setUserOnLeave = async (id) => {
   return data.payload;
 };
 
+export const approveUser = async (id) => {
+  const { data } = await api.put(`/user/${id}/approve`);
+  return data.payload;
+};
+
 export const updateMyProfile = async (payload) => {
   const { data } = await api.put("/user/my/profile", payload);
   return data.payload;

+ 12 - 6
src/components/NotificationDetailDialog.vue

@@ -2,7 +2,7 @@
   <q-dialog ref="dialogRef" @hide="onDialogHide">
     <q-card class="notif-detail-card">
       <q-card-section class="row items-center q-pb-none">
-        <div class="text-h6 text-violet-normal ellipsis" style="max-width: calc(100% - 48px)">
+        <div class="text-h6 text-violet-normal notif-detail-card__title" style="max-width: calc(100% - 48px)">
           {{ item.notification?.title }}
         </div>
         <q-space />
@@ -12,8 +12,8 @@
       <q-separator class="q-mt-sm" />
 
       <q-card-section class="q-pt-md notif-detail-card__scroll">
-        <div v-if="imageUrl" class="notif-detail-card__image q-mb-md">
-          <img :src="imageUrl" alt="" class="notif-detail-card__img" />
+        <div v-if="imageUrl && !imageError" class="notif-detail-card__image q-mb-md">
+          <img :src="imageUrl" alt="" class="notif-detail-card__img" @error="imageError = true" />
         </div>
 
         <div class="text-body2 text-grey-8 notif-detail-card__message">
@@ -60,13 +60,14 @@ const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
 const { t } = useI18n();
 const store = userStore();
 const markedReadId = ref(null);
+const imageError = ref(false);
 
 const imageUrl = computed(() => {
-  const media = props.item.notification?.media?.[0]?.url;
-  if (media) return media;
   const direct = props.item.notification?.image_url;
   if (!direct) return null;
-  return direct.startsWith("http") ? direct : (process.env.API_URL ?? "") + direct;
+  if (direct.startsWith("http")) return direct;
+  const base = (process.env.API_URL ?? "").replace(/\/$/, "");
+  return `${base}/${direct.replace(/^\//, "")}`;
 });
 
 const formatDate = (dateStr) => {
@@ -111,6 +112,11 @@ onMounted(async () => {
     overflow-y: auto;
   }
 
+  &__title {
+    white-space: normal;
+    word-break: break-word;
+  }
+
   &__image {
     width: 100%;
     border-radius: 8px;

+ 10 - 4
src/components/UnreadNotificationsDialog.vue

@@ -35,10 +35,11 @@
             >
               <div class="notif-card__image">
                 <img
-                  v-if="imageUrl(item)"
+                  v-if="imageUrl(item) && !imageErrors.has(item.id)"
                   :src="imageUrl(item)"
                   alt=""
                   class="notif-card__img"
+                  @error="onImageError(item)"
                 />
                 <div v-else class="notif-card__placeholder flex flex-center">
                   <q-icon
@@ -128,6 +129,7 @@ const store = userStore();
 
 const loading = ref(false);
 const notifications = ref([]);
+const imageErrors = ref(new Set());
 
 const localUnreadCount = computed(() => notifications.value.filter((n) => !n.read).length);
 
@@ -147,11 +149,15 @@ const fetchUnread = async () => {
 };
 
 const imageUrl = (item) => {
-  const media = item.notification?.media?.[0]?.url;
-  if (media) return media;
   const direct = item.notification?.image_url;
   if (!direct) return null;
-  return direct.startsWith("http") ? direct : process.env.API_URL + direct;
+  if (direct.startsWith("http")) return direct;
+  const base = (process.env.API_URL ?? "").replace(/\/$/, "");
+  return `${base}/${direct.replace(/^\//, "")}`;
+};
+
+const onImageError = (item) => {
+  imageErrors.value = new Set(imageErrors.value).add(item.id);
 };
 
 const formatDate = (dateStr) => {

+ 27 - 6
src/components/defaults/DefaultTableServerSide.vue

@@ -19,9 +19,7 @@
     @row-click="onRowClick"
   >
     <template v-if="!semTableTop" #top>
-      <div
-        class="flex full-width justify-between items-center"
-      >
+      <div class="row full-width items-end q-gutter-sm">
         <DefaultInput
           v-if="showSearchField"
           v-model="pagination.filter"
@@ -32,16 +30,18 @@
           clearable
           autofocus
           color="violet-normal"
+          class="col-xs-12 col-md"
         >
           <template #prepend>
             <q-icon name="mdi-magnify" />
           </template>
         </DefaultInput>
 
+        <slot name="filters" />
+
         <DefaultSelect
           v-if="showColumnsSelect"
           v-model="visibleColumns"
-          class="q-ml-md"
           multiple
           dense
           outlined
@@ -69,7 +69,7 @@
 
     <template #body-cell-actions="{ row }">
       <q-td auto-width>
-        <q-item-section class="no-wrap" style="flex-direction: row">
+        <q-item-section :top="alignActionsLeft" class="no-wrap" style="flex-direction: row">
           <slot name="body-cell-actions" :row="row" />
           <q-btn
             v-if="deleteFunction"
@@ -157,6 +157,8 @@ const {
   hideNoDataLabel,
   deleteFunction,
   semTableTop,
+  extraFilters,
+  alignActionsLeft,
 } = defineProps({
   columns: {
     type: Array,
@@ -218,6 +220,14 @@ const {
     type: Boolean,
     default: false,
   },
+  extraFilters: {
+    type: Object,
+    default: () => ({}),
+  },
+  alignActionsLeft: {
+    type: Boolean,
+    default: false,
+  },
 });
 
 const { t } = useI18n();
@@ -310,6 +320,7 @@ const onRequest = async () => {
       page: pagination.value.page,
       perPage: pagination.value.rowsPerPage,
       filter: pagination.value.filter,
+      ...extraFilters,
     });
 
     rows.value = response.data.result.data;
@@ -351,12 +362,22 @@ watch(
   },
 );
 
+watch(
+  () => extraFilters,
+  () => {
+    if (loading.value) return;
+    pagination.value.page = 1;
+    onRequest();
+  },
+  { deep: true },
+);
+
 onMounted(async () => {
   await onRequest();
 });
 
 const usableSlots = (slots) => {
-  const handled = ["top", "body-cell-actions", "no-data", "bottom", "loading"];
+  const handled = ["top", "filters", "body-cell-actions", "no-data", "bottom", "loading"];
   return Object.keys(slots).filter((s) => !handled.includes(s));
 };
 

+ 7 - 1
src/i18n/locales/en.json

@@ -481,10 +481,15 @@
     "set_on_leave_title": "Set member on leave",
     "set_on_leave_message": "Confirm putting {name} on leave?",
     "set_on_leave_confirm": "Confirm leave",
+    "approve_title": "Approve registration",
+    "approve_message": "Confirm approval of {name}'s registration?",
+    "approve_confirm": "Confirm approval",
     "import_associados": "Associates",
     "import_sync_result": "{created} created · {updated} updated · {inactivated} inactivated",
     "import_processing": "Import is still processing. Please refresh the page in a moment.",
     "search_placeholder": "Search Members",
+    "filter_by_position": "Filter by position",
+    "filter_by_sector": "Filter by sector",
     "no_dependents": "No dependents registered",
     "remove_photo": "Do you want to remove your profile photo?",
     "kinship": "Kinship",
@@ -582,6 +587,7 @@
       "novos_mes": "New (month)",
       "associados_pendentes": "Pending Members",
       "ultimos_acessos": "Last Accesses",
+      "total_acessos_app": "Serprati App Accesses",
       "association_date": "Association Date",
       "registration_date": "Registration Date"
     },
@@ -626,7 +632,7 @@
     "supplier": "Supplier",
     "stock": "Stock",
     "interests": "Interested",
-    "interested_btn": "INTERESTED",
+    "interested_btn": "Interested",
     "interested_in": "Interested in",
     "media": "Media",
     "add_media": "Add Media",

+ 7 - 1
src/i18n/locales/es.json

@@ -482,10 +482,15 @@
     "set_on_leave_title": "Dar de baja al asociado",
     "set_on_leave_message": "¿Confirma la baja de {name}?",
     "set_on_leave_confirm": "Confirmar baja",
+    "approve_title": "Aprobar registro",
+    "approve_message": "¿Confirma la aprobación del registro de {name}?",
+    "approve_confirm": "Confirmar aprobación",
     "import_associados": "Asociados",
     "import_sync_result": "{created} creados · {updated} actualizados · {inactivated} inactivados",
     "import_processing": "La importación está en progreso. Actualice la página en unos instantes.",
     "search_placeholder": "Buscar por asociados",
+    "filter_by_position": "Filtrar por cargo",
+    "filter_by_sector": "Filtrar por sector",
     "no_dependents": "Ningún dependiente registrado",
     "remove_photo": "¿Deseas eliminar tu foto de perfil?",
     "kinship": "Parentesco",
@@ -583,6 +588,7 @@
       "novos_mes": "Nuevos (mes)",
       "associados_pendentes": "Asociados Pendientes",
       "ultimos_acessos": "Últimos Accesos",
+      "total_acessos_app": "Accesos al App Serprati",
       "association_date": "Fecha de Asociación",
       "registration_date": "Fecha de Registro"
     },
@@ -626,7 +632,7 @@
     "supplier_price": "Precio Proveedor",
     "supplier": "Proveedor",
     "interests": "Interesados",
-    "interested_btn": "INTERESADOS",
+    "interested_btn": "Interesados",
     "interested_in": "Interesados en",
     "media": "Medios",
     "add_media": "Agregar Medio",

+ 7 - 1
src/i18n/locales/pt.json

@@ -482,10 +482,15 @@
     "set_on_leave_title": "Afastar associado",
     "set_on_leave_message": "Confirma o afastamento de {name}?",
     "set_on_leave_confirm": "Confirmar afastamento",
+    "approve_title": "Aprovar cadastro",
+    "approve_message": "Confirma a aprovação do cadastro de {name}?",
+    "approve_confirm": "Confirmar aprovação",
     "import_associados": "Associados",
     "import_sync_result": "{created} criados · {updated} atualizados · {inactivated} inativados",
     "import_processing": "Importação em andamento. Atualize a página em alguns instantes.",
     "search_placeholder": "Buscar por associados",
+    "filter_by_position": "Filtrar por cargo",
+    "filter_by_sector": "Filtrar por setor",
     "no_dependents": "Nenhum dependente cadastrado",
     "remove_photo": "Deseja remover sua foto de perfil?",
     "kinship": "Parentesco",
@@ -583,6 +588,7 @@
       "novos_mes": "Novos (mês)",
       "associados_pendentes": "Associados Pendentes",
       "ultimos_acessos": "Últimos Acessos",
+      "total_acessos_app": "Acessos ao App Serprati",
       "association_date": "Data Associação",
       "registration_date": "Data Cadastro"
     },
@@ -627,7 +633,7 @@
     "supplier": "Fornecedor",
     "stock": "Estoque",
     "interests": "Interessados",
-    "interested_btn": "INTERESSADOS",
+    "interested_btn": "Interessados",
     "interested_in": "Interessados em",
     "media": "Mídias",
     "add_media": "Adicionar Mídia",

+ 10 - 4
src/pages/company-settings/CompanySettingsPage.vue

@@ -20,10 +20,12 @@
                   <div class="col-auto">
                     <q-btn
                       outline
+                      dense
                       color="primary"
                       icon="mdi-upload"
-                      :label="$t('company_settings.hero.upload_image')"
+                      padding="8px 10px"
                       :loading="uploadingImage"
+                      :title="$t('company_settings.hero.upload_image')"
                       @click="triggerImageUpload"
                     />
                     <input
@@ -37,10 +39,12 @@
                   <div v-if="settings.hero_background_url" class="col-auto">
                     <q-btn
                       flat
+                      dense
                       color="negative"
                       icon="mdi-delete"
-                      :label="$t('company_settings.hero.remove_image')"
+                      padding="8px 10px"
                       :loading="removingImage"
+                      :title="$t('company_settings.hero.remove_image')"
                       @click="onRemoveImage"
                     />
                   </div>
@@ -116,12 +120,14 @@
 
               <div class="col-12 flex justify-end">
                 <q-btn
+                  dense
                   color="primary"
                   icon="mdi-content-save"
-                  :label="$t('common.actions.save')"
                   type="submit"
+                  padding="8px 10px"
                   :loading="savingSettings"
                   :disable="!hasUpdatedFields"
+                  :title="$t('common.actions.save')"
                 />
               </div>
             </div>
@@ -136,9 +142,9 @@
               {{ $t("company_settings.section.benefits") }}
             </div>
             <q-btn
+              dense
               color="primary"
               icon="mdi-plus"
-              :label="$t('common.actions.add')"
               padding="8px 8px"
               @click="onAddBenefit"
             />

+ 5 - 2
src/pages/dashboard/DashboardPage.vue

@@ -40,7 +40,7 @@
             :api-call="activeApiCall"
             :add-item="false"
             sem-table-top
-            :show-search-field="activeCard !== 'ultimos_acessos'"
+            :show-search-field="!['ultimos_acessos', 'total_acessos_app'].includes(activeCard)"
           >
             <template #body-cell-status="{ row }">
               <q-td>
@@ -100,6 +100,7 @@ const statCards = [
   { key: "novos_mes",            icon: "mdi-account-plus",   labelKey: "dashboard.stats.novos_mes" },
   { key: "associados_pendentes", icon: "mdi-account-alert",  labelKey: "dashboard.stats.associados_pendentes" },
   { key: "ultimos_acessos",      icon: "mdi-login-variant",  labelKey: "dashboard.stats.ultimos_acessos" },
+  { key: "total_acessos_app",    icon: "mdi-cellphone-check", labelKey: "dashboard.stats.total_acessos_app" },
 ];
 
 // Colunas por tipo de card
@@ -134,7 +135,7 @@ const tableColumns = computed(() => {
   if (!activeCard.value) return [];
   if (activeCard.value === "contratos_a_vencer") return columnsContratosAVencer.value;
   if (activeCard.value === "parceiros" || activeCard.value === "novos_mes") return columnsParceiros.value;
-  if (activeCard.value === "ultimos_acessos") return columnsAccessLogs.value;
+  if (activeCard.value === "ultimos_acessos" || activeCard.value === "total_acessos_app") return columnsAccessLogs.value;
   return columnsAssociados.value;
 });
 
@@ -155,6 +156,8 @@ const activeApiCall = computed(() => {
       return (p) => getPartnerAgreementsPaginated({ ...p, createdMonth: "current" });
     case "ultimos_acessos":
       return (p) => getAccessLogsPaginated({ ...p, last_per_user: true });
+    case "total_acessos_app":
+      return (p) => getAccessLogsPaginated({ ...p, type: "associado", last_per_user: true });
     default:
       return null;
   }

+ 79 - 8
src/pages/gestao-associados/GestaoAssociadosPage.vue

@@ -13,34 +13,39 @@
         <div class="flex gap-sm q-mt-md">
           <q-btn
             unelevated
+            dense
+            no-caps
             class="btn-gradient"
             :label="$t('associado.import_afastamentos')"
             icon="mdi-upload"
-            padding="8px 12px"
+            padding="6px 10px"
           />
           <q-btn
             unelevated
+            dense
+            no-caps
             class="btn-gradient"
             :label="$t('associado.import_associados')"
             icon="mdi-upload"
-            padding="8px 12px"
+            padding="6px 10px"
             :loading="importing"
             @click="onImportClick"
           />
           <q-btn
             unelevated
+            dense
             class="btn-gradient"
             icon="mdi-clock-outline"
-            padding="8px 12px"
+            padding="6px 10px"
             :title="$t('import_log.history_title')"
             @click="onOpenImportHistory"
           />
           <q-btn
             unelevated
+            dense
             class="btn-gradient"
-            :label="$t('common.actions.new')"
             icon="mdi-plus"
-            padding="8px 12px"
+            padding="6px 10px"
             @click="onAddItem"
           />
         </div>
@@ -52,11 +57,36 @@
       :columns="columns"
       :api-call="getAssociadosPaginated"
       :add-item="false"
+      :extra-filters="extraFilters"
+      align-actions-left
       open-item
       @on-row-click="onRowClick"
     >
+      <template #filters>
+        <PositionSelect
+          v-model="selectedPosition"
+          clearable
+          dense
+          outlined
+          color="violet-normal"
+          class="col-xs-12 col-sm-6 col-md-auto"
+          style="min-width: 180px"
+          :placeholder="$t('associado.filter_by_position')"
+        />
+        <SectorSelect
+          v-model="selectedSector"
+          clearable
+          dense
+          outlined
+          color="violet-normal"
+          class="col-xs-12 col-sm-6 col-md-auto"
+          style="min-width: 180px"
+          :placeholder="$t('associado.filter_by_sector')"
+        />
+      </template>
+
       <template #body-cell-actions="{ row }">
-        <div class="row no-wrap items-center" style="gap: 4px">
+        <div class="row no-wrap justify-start items-center" style="gap: 4px">
           <q-btn flat round dense color="violet-normal" icon="mdi-pencil" @click.stop="onRowClick({ row })" />
           <q-btn
             flat round dense
@@ -67,6 +97,16 @@
           />
           <q-btn flat round dense color="violet-normal" icon="mdi-calendar" @click.stop />
           <q-btn flat round dense color="violet-normal" icon="mdi-sofa" @click.stop />
+          <q-btn
+            v-if="row.status === 'pending' || row.status?.value === 'pending'"
+            flat 
+            round 
+            dense 
+            color="violet-normal"
+            icon="mdi-check-circle-outline"
+            :title="$t('associado.approve_confirm')"
+            @click.stop="onApprove(row)"
+          />
         </div>
       </template>
 
@@ -92,11 +132,13 @@ import { ref, computed, defineAsyncComponent, useTemplateRef } from "vue";
 import { useQuasar } from "quasar";
 import { useI18n } from "vue-i18n";
 import { permissionStore } from "src/stores/permission";
-import { getAssociadosPaginated, importAssociados, setUserOnLeave } from "src/api/user";
+import { getAssociadosPaginated, importAssociados, setUserOnLeave, approveUser } from "src/api/user";
 import { getStatusColor, getStatusI18nKey } from "src/helpers/utils";
 import { useImportPoller } from "src/composables/useImportPoller";
 import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
 import DefaultTableServerSide from "src/components/defaults/DefaultTableServerSide.vue";
+import PositionSelect from "src/components/selects/PositionSelect.vue";
+import SectorSelect from "src/components/selects/SectorSelect.vue";
 import AccessLogsTable from "./components/AccessLogsTable.vue";
 
 const AddEditAssociadoDialog = defineAsyncComponent(
@@ -113,6 +155,13 @@ const tableRef = ref(null);
 const importFileInput = useTemplateRef("importFileInput");
 const { polling: importing, start: startPolling } = useImportPoller();
 
+const selectedPosition = ref(null);
+const selectedSector = ref(null);
+const extraFilters = computed(() => ({
+  position_id: selectedPosition.value?.value,
+  sector_id: selectedSector.value?.value,
+}));
+
 const columns = computed(() => [
   {
     name: "registration",
@@ -157,7 +206,7 @@ const columns = computed(() => [
   {
     name: "actions",
     label: t("common.terms.actions"),
-    align: "right",
+    align: "center",
     required: true,
     width: "15%",
   },
@@ -219,6 +268,28 @@ const onSetOnLeave = (row) => {
   });
 };
 
+const onApprove = (row) => {
+  if (!permission_store.getAccess("associado", "edit")) {
+    $q.notify({ type: "negative", message: t("validation.permissions.edit") });
+    return;
+  }
+
+  $q.dialog({
+    title: t("associado.approve_title"),
+    message: t("associado.approve_message", { name: row.name }),
+    cancel: { flat: true, label: t("common.actions.cancel"), color: "grey-7" },
+    ok: { unelevated: true, label: t("associado.approve_confirm"), color: "violet-normal" },
+    persistent: true,
+  }).onOk(async () => {
+    try {
+      await approveUser(row.id);
+      tableRef.value?.refresh();
+    } catch {
+      // silent
+    }
+  });
+};
+
 const onOpenImportHistory = () => {
   $q.dialog({ component: ImportHistoryDialog, componentProps: { type: 'associado' } });
 };

+ 4 - 4
src/pages/loja/LojaPage.vue

@@ -5,10 +5,10 @@
         <div class="flex gap-sm q-mt-md">
           <q-btn
             unelevated
+            dense
             class="btn-gradient"
-            :label="$t('common.actions.new')"
             icon="mdi-plus"
-            padding="8px 12px"
+            padding="6px 10px"
             @click="onAddItem"
           />
         </div>
@@ -169,10 +169,10 @@
                     unelevated
                     size="sm"
                     class="btn-gradient q-mt-xs"
-                    :label="$t('loja.interested_btn')"
                     icon="mdi-thumb-up"
                     padding="5px 8px"
                     style="width: 100%"
+                    :title="$t('loja.interested_btn')"
                     @click="onInterests(item)"
                   />
                 </div>
@@ -276,7 +276,7 @@ onMounted(async () => {
 
     itemsData.forEach((item) => {
       if (item.variations?.length) {
-        selectedVariations.value[item.id] = item.variations ?? item.variations[0];
+        selectedVariations.value[item.id] = item.variations[0];
       }
     });
   } catch (e) {

+ 6 - 5
src/pages/loja/StoreItemFormPage.vue

@@ -5,10 +5,10 @@
         <div class="flex items-center gap-sm q-mt-md">
           <q-btn
             flat
+            dense
             icon="mdi-arrow-left"
-            :label="$t('common.actions.back')"
             color="violet-normal"
-            padding="8px 12px"
+            padding="6px 10px"
             @click="router.push({ name: 'LojaPage' })"
           />
         </div>
@@ -171,10 +171,10 @@
                     <div class="col-auto q-pb-xs">
                       <q-btn
                         unelevated
+                        dense
                         color="purple-8"
-                        :label="$t('loja.add_variation')"
                         icon="mdi-plus"
-                        padding="6px 12px"
+                        padding="6px 10px"
                         :disable="!newVariationLabel.trim()"
                         :loading="addingVariation"
                         @click="addVariation"
@@ -231,11 +231,12 @@
               <div class="flex justify-end q-mt-lg">
                 <q-btn
                   unelevated
+                  dense
                   type="submit"
                   class="btn-gradient"
                   :label="$t('common.actions.save')"
                   :loading="loading"
-                  padding="10px 24px"
+                  padding="8px 16px"
                 />
               </div>
           </div>

+ 7 - 5
src/pages/parceiros-convenios/ConveniosMedicosPage.vue

@@ -13,27 +13,29 @@
         <div v-if="isAdministrador" class="flex gap-sm q-mt-md">
           <q-btn
             unelevated
+            dense
             class="btn-gradient"
-            :label="$t('parceiro.import_convenios')"
             icon="mdi-upload"
-            padding="8px 12px"
+            padding="6px 10px"
             :loading="importingConvenios"
+            :title="$t('parceiro.import_convenios')"
             @click="onImportConveniosClick"
           />
           <q-btn
             unelevated
+            dense
             class="btn-gradient"
             icon="mdi-clock-outline"
-            padding="8px 12px"
+            padding="6px 10px"
             :title="$t('import_log.history_title')"
             @click="onOpenImportHistory"
           />
           <q-btn
             unelevated
+            dense
             class="btn-gradient"
-            :label="$t('common.actions.add')"
             icon="mdi-plus"
-            padding="8px 12px"
+            padding="6px 10px"
             @click="onAddItem"
           />
         </div>

+ 7 - 5
src/pages/parceiros-convenios/ParceirosConveniosPage.vue

@@ -13,27 +13,29 @@
         <div v-if="isAdministrador" class="flex gap-sm q-mt-md">
           <q-btn
             unelevated
+            dense
             class="btn-gradient"
-            :label="$t('parceiro.import_parceiros')"
             icon="mdi-upload"
-            padding="8px 12px"
+            padding="6px 10px"
             :loading="importingParceiros"
+            :title="$t('parceiro.import_parceiros')"
             @click="onImportParceirosClick"
           />
           <q-btn
             unelevated
+            dense
             class="btn-gradient"
             icon="mdi-clock-outline"
-            padding="8px 12px"
+            padding="6px 10px"
             :title="$t('import_log.history_title')"
             @click="onOpenImportHistory"
           />
           <q-btn
             unelevated
+            dense
             class="btn-gradient"
-            :label="$t('common.actions.add')"
             icon="mdi-plus"
-            padding="8px 12px"
+            padding="6px 10px"
             @click="onAddItem"
           />
         </div>

+ 3 - 2
src/pages/relatorios/RelatoriosPage.vue

@@ -4,11 +4,12 @@
       <template #after>
         <q-btn
           unelevated
+          dense
           class="btn-export"
-          :label="$t('relatorio.exportar_excel')"
           icon="mdi-download"
-          padding="8px 16px"
+          padding="6px 10px"
           :loading="exportLoading"
+          :title="$t('relatorio.exportar_excel')"
           @click="onExport"
         />
       </template>