Ver Fonte

feat(users): altera rota de usuarios, default table para seguir o padrao e ajusta userpage de franqueada

ebagabee há 2 semanas atrás
pai
commit
9e49169fd4

+ 35 - 15
src/components/defaults/DefaultTable.vue

@@ -23,21 +23,41 @@
         <div v-if="title" class="column text-h6">
           <span>{{ title }}</span>
           <span class="text-body2">{{
-            rows.length + " " + $t("common.ui.table.records_found")
+            `${rows.length} ${descricao} ${feminino ? "cadastradas" : "cadastrados"}`
           }}</span>
         </div>
+
+        <slot name="top" :rows="rows" />
+
+        <q-space />
+
+        <q-btn
+          v-if="addItem"
+          color="primary"
+          style="width: 40px; height: 40px"
+          icon="mdi-plus"
+          :outline="outlineAdd"
+          @click="onAddItem"
+        >
+        </q-btn>
+      </div>
+
+      <div class="flex full-width align-center q-mb-md" style="gap: 1rem">
         <DefaultInput
           v-if="showSearchField"
           v-model="filter"
           debounce="250"
+          label="Busque por Unidade, status ou Responsavel"
           :placeholder="$t('common.actions.search')"
           clearable
-          autofocus
-          class="q-mt-sm q-ml-sm"
+          class="q-mt-sm full-width search-input"
           color="primary"
+          bg-color="transparent"
+          dense
+          input-class="q-pl-xs"
         >
-          <template #append>
-            <q-icon name="mdi-magnify" />
+          <template #prepend>
+            <q-icon name="mdi-magnify" color="grey-6" />
           </template>
         </DefaultInput>
         <DefaultSelect
@@ -52,16 +72,6 @@
           style="width: 150px"
           options-selected-class="text-bold"
         />
-        <slot name="top" :rows="rows" />
-        <q-btn
-          v-if="addItem"
-          color="primary"
-          padding="10px 16px"
-          :outline="outlineAdd"
-          :label="$t('common.actions.add')"
-          @click="onAddItem"
-        >
-        </q-btn>
       </div>
     </template>
 
@@ -150,6 +160,8 @@ const emit = defineEmits(["onRowClick", "onAddItem", "noRows"]);
 const {
   columns,
   apiCall,
+  descricao,
+  feminino,
   outlineAdd,
   openItem,
   openItemRoute,
@@ -173,6 +185,14 @@ const {
     type: Function,
     default: null,
   },
+  descricao: {
+    type: String,
+    default: "linhas",
+  },
+  feminino: {
+    type: Boolean,
+    default: true,
+  },
   outlineAdd: {
     type: Boolean,
     default: false,

+ 195 - 0
src/pages/users/UserActionPage.vue

@@ -0,0 +1,195 @@
+<template>
+  <div>
+    <DefaultHeaderPage title="Cadastro de Usuário" />
+
+    <div class="q-pa-md">
+      <div class="column justify-center items-center q-mb-lg">
+        <div class="q-mb-md">
+          <q-avatar size="80px" color="grey-3">
+            <q-icon name="mdi-account" size="48px" color="grey-6" />
+            <q-btn
+              round
+              dense
+              color="primary"
+              icon="mdi-camera"
+              size="xs"
+              style="position: absolute; bottom: 0; right: 0"
+              @click="triggerFileInput"
+            />
+          </q-avatar>
+          <input
+            ref="fileInputRef"
+            type="file"
+            accept="image/*"
+            style="display: none"
+            @change="onAvatarChange"
+          />
+        </div>
+
+        <div class="row full-width q-mt-md q-col-gutter-sm">
+          <DefaultSelect
+            v-model="form.state"
+            label="Estado / UF"
+            class="col-6"
+            outlined
+            emit-value
+            map-options
+            :options="stateOptions"
+          />
+
+          <DefaultSelect
+            v-model="form.unit"
+            label="Unidade"
+            class="col-6"
+            outlined
+            emit-value
+            map-options
+            :options="unitOptions"
+          />
+
+          <DefaultSelect
+            v-model="form.role"
+            label="Tipo de Usuário"
+            class="col-6"
+            outlined
+            emit-value
+            map-options
+            :options="roleOptions"
+          />
+
+          <DefaultInput
+            v-model="form.cpf"
+            label="CPF"
+            class="col-6"
+            outlined
+          />
+
+          <DefaultInput
+            v-model="form.name"
+            label="Nome"
+            class="col-6"
+            outlined
+          />
+
+          <DefaultPasswordInput
+            v-model="form.password"
+            label="Senha"
+            class="col-6"
+            outlined
+          />
+
+          <DefaultInput
+            v-model="form.surname"
+            label="Sobrenome"
+            class="col-6"
+            outlined
+          />
+
+          <DefaultPasswordInput
+            v-model="form.password_confirmation"
+            label="Repetir Senha"
+            class="col-6"
+            outlined
+          />
+
+          <DefaultInput
+            v-model="form.email"
+            label="E-mail"
+            class="col-6"
+            outlined
+            type="email"
+          />
+
+          <div class="col-6 flex items-center">
+            <q-btn
+              label="Gerar senha segura"
+              icon="mdi-thumb-up-outline"
+              color="primary"
+              @click="generatePassword"
+            />
+          </div>
+        </div>
+
+        <div class="row justify-end q-mt-md full-width">
+          <q-btn
+            label="SALVAR"
+            icon-right="mdi-check"
+            color="primary"
+            @click="onSave"
+          />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, useTemplateRef } from "vue";
+import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
+import DefaultInput from "src/components/defaults/DefaultInput.vue";
+import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
+import DefaultPasswordInput from "src/components/defaults/DefaultPasswordInput.vue";
+
+const fileInputRef = useTemplateRef("fileInputRef");
+
+const form = ref({
+  state: null,
+  unit: null,
+  role: null,
+  cpf: null,
+  name: null,
+  surname: null,
+  email: null,
+  password: null,
+  password_confirmation: null,
+});
+
+const stateOptions = ref([
+  { label: "Paraná", value: "PR" },
+  { label: "São Paulo", value: "SP" },
+  { label: "Santa Catarina", value: "SC" },
+]);
+
+const unitOptions = ref([
+  { label: "Toledo-PR", value: "toledo" },
+  { label: "Arapongas-PR", value: "arapongas" },
+  { label: "Curitiba-PR", value: "curitiba" },
+  { label: "Londrina-PR", value: "londrina" },
+  { label: "Ponta Grossa-PR", value: "ponta_grossa" },
+  { label: "Maringá-PR", value: "maringa" },
+  { label: "Cascavel-PR", value: "cascavel" },
+]);
+
+const roleOptions = ref([
+  { label: "Neurotainer", value: "neurotainer" },
+  { label: "Assessor", value: "assessor" },
+  { label: "Marketing", value: "marketing" },
+  { label: "Comercial", value: "comercial" },
+  { label: "Gestor", value: "gestor" },
+  { label: "Administrativo", value: "administrativo" },
+  { label: "Recepção", value: "recepcao" },
+]);
+
+function triggerFileInput() {
+  fileInputRef.value?.click();
+}
+
+function onAvatarChange(event) {
+  const file = event.target.files[0];
+  console.log("Avatar file selected:", file);
+}
+
+function generatePassword() {
+  const chars =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%";
+  const password = Array.from({ length: 12 }, () =>
+    chars.charAt(Math.floor(Math.random() * chars.length)),
+  ).join("");
+  form.value.password = password;
+  form.value.password_confirmation = password;
+}
+
+function onSave() {
+  console.log("Saving user:", form.value);
+}
+</script>

+ 175 - 1
src/pages/users/UsersPage.vue

@@ -2,10 +2,184 @@
   <div>
     <DefaultHeaderPage title="Usuários" show-filter-icon />
 
-    <div></div>
+    <div class="row q-col-gutter-x-md q-pa-sm">
+      <q-select
+        v-model="funcaoSelected"
+        label="Selecione a Função"
+        class="col-3"
+        color="secondary"
+        emit-value
+        map-options
+        :options="funcaoOptions"
+      />
+
+      <q-select
+        v-model="unitSelected"
+        label="Selecione a Unidade"
+        class="col-3"
+        color="secondary"
+        emit-value
+        map-options
+        :options="unitOptions"
+      />
+    </div>
+
+    <div class="q-px-sm">
+      <DefaultTable
+        v-model:rows="rows"
+        title="Lista de Usuários"
+        :columns
+        descricao="Usuários"
+        no-api-call
+        add-item
+        add-item-route="UserAddPage"
+      >
+        <template #body-cell-status="{ row }">
+          <q-td align="center">
+            <q-badge
+              :color="row.status === 'active' ? 'positive' : 'warning'"
+              :label="row.status === 'active' ? 'Ativo' : 'Inativo'"
+            />
+          </q-td>
+        </template>
+
+        <template #body-cell-actions>
+          <q-td auto-width>
+            <q-item-section class="no-wrap" style="flex-direction: row">
+              <q-btn
+                outline
+                icon="mdi-account-edit-outline"
+                style="width: 36px"
+                class="q-mr-sm"
+                @click.prevent.stop="() => {}"
+              />
+              <q-btn
+                outline
+                icon="mdi-trash-can-outline"
+                style="width: 36px"
+                class="q-mr-sm"
+                @click.prevent.stop="() => {}"
+              />
+            </q-item-section>
+          </q-td>
+        </template>
+      </DefaultTable>
+    </div>
   </div>
 </template>
 
 <script setup>
 import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
+import DefaultTable from "src/components/defaults/DefaultTable.vue";
+import { ref } from "vue";
+
+const funcaoSelected = ref(null);
+const unitSelected = ref(null);
+
+const funcaoOptions = ref([
+  { label: "Todas", value: null },
+  { label: "Neurotainer", value: "neurotainer" },
+  { label: "Assessor", value: "assessor" },
+  { label: "Marketing", value: "marketing" },
+  { label: "Comercial", value: "comercial" },
+  { label: "Gestor", value: "gestor" },
+  { label: "Administrativo", value: "administrativo" },
+  { label: "Recepção", value: "recepcao" },
+]);
+
+const unitOptions = ref([
+  { label: "Todas", value: null },
+  { label: "Toledo-PR", value: "toledo" },
+  { label: "Arapongas-PR", value: "arapongas" },
+  { label: "Curitiba-PR", value: "curitiba" },
+  { label: "Londrina-PR", value: "londrina" },
+  { label: "Ponta Grossa-PR", value: "ponta_grossa" },
+  { label: "Maringá-PR", value: "maringa" },
+  { label: "Cascavel-PR", value: "cascavel" },
+]);
+
+const columns = ref([
+  {
+    name: "name",
+    label: "Nome",
+    field: "name",
+    align: "left",
+  },
+  {
+    name: "unit",
+    label: "Unidade",
+    field: "unit",
+    align: "left",
+  },
+  {
+    name: "role",
+    label: "Função",
+    field: "role",
+    align: "left",
+  },
+  {
+    name: "status",
+    label: "Status",
+    field: "status",
+    align: "center",
+  },
+  {
+    name: "actions",
+    label: "Ações",
+    field: null,
+    align: "center",
+  },
+]);
+
+const rows = ref([
+  {
+    id: 1,
+    name: "Heloisa Faria",
+    unit: "Toledo-PR",
+    role: "Neurotainer",
+    status: "inactive",
+  },
+  {
+    id: 2,
+    name: "Carol",
+    unit: "Arapongas-PR",
+    role: "Assessor",
+    status: "active",
+  },
+  {
+    id: 3,
+    name: "Marcelo Souza",
+    unit: "Curitiba-PR",
+    role: "Marketing",
+    status: "active",
+  },
+  {
+    id: 4,
+    name: "Ana Lúcia",
+    unit: "Londrina-PR",
+    role: "Comercial",
+    status: "active",
+  },
+  {
+    id: 5,
+    name: "Ricardo Silva",
+    unit: "Ponta Grossa-PR",
+    role: "Gestor",
+    status: "active",
+  },
+  {
+    id: 6,
+    name: "Juliana Civita",
+    unit: "Maringá-PR",
+    role: "Administrativo",
+    status: "active",
+  },
+  {
+    id: 7,
+    name: "Fernando Almeida",
+    unit: "Cascavel-PR",
+    role: "Recepção",
+    status: "active",
+  },
+]);
 </script>

+ 23 - 0
src/router/routes/config.route.js

@@ -86,6 +86,29 @@ export default [
       ],
     },
   },
+  {
+    path: "/users/create",
+    name: "UserAddPage",
+    component: () => import("pages/users/UserActionPage.vue"),
+    meta: {
+      title: {
+        value: "Cadastro de Usuário",
+        translate: false,
+      },
+      requireAuth: true,
+      requiredPermission: "config.user",
+      breadcrumbs: [
+        {
+          name: "UsersPage",
+          title: "Usuários",
+        },
+        {
+          name: "UserAddPage",
+          title: "Cadastro de Usuário",
+        },
+      ],
+    },
+  },
   {
     path: "/users",
     name: "UsersPage",