Forráskód Böngészése

ajustes configurações e usuarios

leonardo 3 hónapja
szülő
commit
5df0a02ccf

+ 2 - 2
dist/index.html

@@ -6,8 +6,8 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1" />
     <link rel="icon" type="image/x-icon" href="/favicon.ico?v=2" />
     <title>ORÁCULO</title>
-    <script type="module" crossorigin src="/assets/index-D4o7qFcq.js"></script>
-    <link rel="stylesheet" crossorigin href="/assets/index-CfNeBKOp.css">
+    <script type="module" crossorigin src="/assets/index-Cg266NFj.js"></script>
+    <link rel="stylesheet" crossorigin href="/assets/index-DiByyltO.css">
   </head>
   <body class="bg-background">
     <noscript>

+ 6 - 0
src/api/users.js

@@ -0,0 +1,6 @@
+import { apiFetch } from "./client.js";
+
+export async function listUsers() {
+  const payload = await apiFetch("/api/users");
+  return Array.isArray(payload?.items) ? payload.items : [];
+}

+ 29 - 0
src/composables/useUsers.js

@@ -0,0 +1,29 @@
+import { ref } from "vue";
+import { listUsers } from "../api/users.js";
+
+const users = ref([]);
+const loading = ref(false);
+const error = ref("");
+
+export function useUsers() {
+  async function loadUsers() {
+    loading.value = true;
+    error.value = "";
+
+    try {
+      users.value = await listUsers();
+    } catch (err) {
+      users.value = [];
+      error.value = err?.message || "Erro ao carregar usuarios.";
+    } finally {
+      loading.value = false;
+    }
+  }
+
+  return {
+    users,
+    loading,
+    error,
+    loadUsers
+  };
+}

+ 1 - 0
src/layout/LayoutSistema.vue

@@ -75,6 +75,7 @@ const tituloPagina = computed(() => {
   if (nome === "conversas-pesquisar") return "Pesquisar conversas";
   if (nome === "conversas-historico") return "Histórico";
   if (nome === "configuracoes") return "Configurações";
+  if (nome === "usuarios") return "Usuários";
   return "Oráculo";
 });
 

+ 2 - 0
src/router/index.js

@@ -3,6 +3,7 @@ import PaginaInicialView from "../views/pagina-inicial/PaginaInicialView.vue";
 import ConversasHistoricoView from "../views/conversas/ConversasHistoricoView.vue";
 import ConversasPesquisarView from "../views/conversas/ConversasPesquisarView.vue";
 import ConfiguracoesView from "../views/configuracoes/ConfiguracoesView.vue";
+import UsuariosView from "../views/usuarios/UsuariosView.vue";
 import LoginView from "../views/auth/LoginView.vue";
 import { useAuth } from "../composables/useAuth.js";
 
@@ -14,6 +15,7 @@ export const router = createRouter({
     { path: "/conversas/historico", name: "conversas-historico", component: ConversasHistoricoView, meta: { requiresAuth: true } },
     { path: "/conversas/pesquisar", name: "conversas-pesquisar", component: ConversasPesquisarView, meta: { requiresAuth: true } },
     { path: "/configuracoes", name: "configuracoes", component: ConfiguracoesView, meta: { requiresAuth: true } },
+    { path: "/usuarios", name: "usuarios", component: UsuariosView, meta: { requiresAuth: true } },
     { path: "/:pathMatch(.*)*", redirect: "/" }
   ]
 });

+ 149 - 59
src/views/configuracoes/ConfiguracoesView.vue

@@ -1,21 +1,159 @@
 <script setup>
+import { useRouter } from "vue-router";
 import LayoutSistema from "../../layout/LayoutSistema.vue";
+
+const router = useRouter();
+
+function irParaUsuarios() {
+  router.push({ name: "usuarios" });
+}
 </script>
 
 <template>
   <LayoutSistema>
     <div
-      class="min-h-[calc(100vh-var(--layout-header-height))] flex items-start pt-8 justify-center"
+      class="min-h-[calc(100vh-var(--layout-header-height))] flex items-start justify-center pt-8"
     >
-      <section
-        class="w-full max-w-[980px] rounded-2xl border border-gray-200 bg-gray-100/50 p-6 shadow-sm backdrop-blur-md dark:border-gray-700 dark:bg-secondary/50"
-      >
-        <div class="flex items-start gap-4">
+      <div class="w-full max-w-[980px] space-y-6">
+        <section
+          class="rounded-2xl border border-gray-200 bg-gray-100/50 p-6 shadow-sm backdrop-blur-md dark:border-gray-700 dark:bg-secondary/50"
+        >
+          <div class="flex items-start gap-4">
+            <div
+              class="flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary dark:bg-primary/20"
+            >
+              <svg
+                class="h-6 w-6"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="1.8"
+              >
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M4 21v-7"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M4 10V3"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M12 21v-9"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M12 8V3"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M20 21v-5"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M20 12V3"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M1 14h6"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M9 8h6"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M17 16h6"
+                />
+              </svg>
+            </div>
+            <div class="min-w-0">
+              <h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100">
+                Configurações do Sistema
+              </h2>
+              <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
+                Gerencie usuários e algumas preferências da plataforma.
+              </p>
+            </div>
+          </div>
+        </section>
+
+        <section>
           <div
-            class="flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary dark:bg-primary/20"
+            class="mb-3 text-xs font-semibold uppercase tracking-[0.16em] text-gray-500 dark:text-gray-400"
+          >
+            Usuários & Acesso
+          </div>
+
+          <button
+            type="button"
+            class="grid w-full max-w-[620px] grid-cols-[auto_1fr_auto] items-center gap-4 rounded-2xl border border-gray-200 bg-background/70 p-5 text-left shadow-sm transition-colors hover:border-primary/40 dark:border-gray-700 dark:bg-background/20 dark:hover:border-primary/40"
+            @click="irParaUsuarios"
           >
+            <div
+              class="flex h-14 w-14 items-center justify-center rounded-2xl bg-[linear-gradient(135deg,var(--primary-500),#4f46e5)] text-white shadow-[0_10px_24px_rgba(37,99,235,0.28)]"
+            >
+              <svg
+                class="h-7 w-7"
+                viewBox="0 0 24 24"
+                fill="none"
+                stroke="currentColor"
+                stroke-width="1.8"
+              >
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M16 19a4 4 0 0 0-8 0"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M12 12a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M7.5 18.5A3.5 3.5 0 0 0 4 15"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M16.5 18.5A3.5 3.5 0 0 1 20 15"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M5 12a2.25 2.25 0 1 0 0-4.5A2.25 2.25 0 0 0 5 12Z"
+                />
+                <path
+                  stroke-linecap="round"
+                  stroke-linejoin="round"
+                  d="M19 12a2.25 2.25 0 1 0 0-4.5A2.25 2.25 0 0 0 19 12Z"
+                />
+              </svg>
+            </div>
+
+            <div class="min-w-0">
+              <div class="text-lg font-semibold text-gray-900 dark:text-gray-100">
+                Usuários
+              </div>
+              <div class="mt-1 text-sm text-gray-500 dark:text-gray-400">
+                Cadastre e gerencie usuários, perfis e níveis de acesso ao
+                sistema.
+              </div>
+            </div>
+
             <svg
-              class="h-6 w-6"
+              class="h-5 w-5 text-gray-400 dark:text-gray-500"
               viewBox="0 0 24 24"
               fill="none"
               stroke="currentColor"
@@ -24,60 +162,12 @@ import LayoutSistema from "../../layout/LayoutSistema.vue";
               <path
                 stroke-linecap="round"
                 stroke-linejoin="round"
-                d="M4 21v-7"
-              />
-              <path
-                stroke-linecap="round"
-                stroke-linejoin="round"
-                d="M4 10V3"
-              />
-              <path
-                stroke-linecap="round"
-                stroke-linejoin="round"
-                d="M12 21v-9"
-              />
-              <path
-                stroke-linecap="round"
-                stroke-linejoin="round"
-                d="M12 8V3"
-              />
-              <path
-                stroke-linecap="round"
-                stroke-linejoin="round"
-                d="M20 21v-5"
-              />
-              <path
-                stroke-linecap="round"
-                stroke-linejoin="round"
-                d="M20 12V3"
-              />
-              <path
-                stroke-linecap="round"
-                stroke-linejoin="round"
-                d="M1 14h6"
-              />
-              <path
-                stroke-linecap="round"
-                stroke-linejoin="round"
-                d="M9 8h6"
-              />
-              <path
-                stroke-linecap="round"
-                stroke-linejoin="round"
-                d="M17 16h6"
+                d="m9 6 6 6-6 6"
               />
             </svg>
-          </div>
-          <div class="min-w-0">
-            <h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100">
-              Configurações do Sistema
-            </h2>
-            <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
-              Gerencie usuarios e algumas preferências da plataforma.
-            </p>
-          </div>
-        </div>
-      </section>
+          </button>
+        </section>
+      </div>
     </div>
   </LayoutSistema>
 </template>

+ 108 - 0
src/views/usuarios/UsuariosView.vue

@@ -0,0 +1,108 @@
+<script setup>
+import { computed, onMounted } from "vue";
+import LayoutSistema from "../../layout/LayoutSistema.vue";
+import { useUsers } from "../../composables/useUsers.js";
+
+const { users, loading, error, loadUsers } = useUsers();
+
+const totalUsuarios = computed(() => users.value?.length ?? 0);
+
+function formatarStatus(status) {
+  return String(status) === "0" ? "Inativo" : "Ativo";
+}
+
+function classeStatus(status) {
+  return String(status) === "0"
+    ? "border-red-200 bg-red-100 text-red-700 dark:border-red-500/20 dark:bg-red-500/10 dark:text-red-300"
+    : "border-emerald-200 bg-emerald-100 text-emerald-700 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300";
+}
+
+onMounted(async () => {
+  await loadUsers();
+});
+</script>
+
+<template>
+  <LayoutSistema>
+    <section
+      class="rounded-2xl border border-gray-200 bg-gray-100/50 p-6 shadow-sm backdrop-blur-md dark:border-gray-700 dark:bg-secondary/50"
+    >
+      <div class="flex items-start justify-between gap-4">
+        <div>
+          <h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100">
+            Usuários
+          </h2>
+          <p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
+            Lista dos usuários cadastrados no sistema.
+          </p>
+        </div>
+        <div
+          class="rounded-xl border border-primary/15 bg-primary/10 px-3 py-2 text-sm font-medium text-primary dark:border-primary/20 dark:bg-primary/15"
+        >
+          {{ totalUsuarios }} usuario{{ totalUsuarios === 1 ? "" : "s" }}
+        </div>
+      </div>
+
+      <div v-if="loading" class="mt-6 text-sm text-gray-500 dark:text-gray-400">
+        Carregando usuários...
+      </div>
+
+      <div
+        v-else-if="error"
+        class="mt-6 rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700 dark:border-red-500/20 dark:bg-red-500/10 dark:text-red-300"
+      >
+        {{ error }}
+      </div>
+
+      <div
+        v-else-if="!users.length"
+        class="mt-6 rounded-xl border border-dashed border-gray-300 px-4 py-6 text-sm text-gray-500 dark:border-gray-600 dark:text-gray-400"
+      >
+        Nenhum usuário encontrado.
+      </div>
+
+      <div v-else class="mt-6 grid gap-3">
+        <article
+          v-for="usuario in users"
+          :key="usuario.Id"
+          class="rounded-2xl border border-gray-200 bg-background/70 p-4 shadow-sm dark:border-gray-700 dark:bg-background/20"
+        >
+          <div
+            class="flex flex-col gap-3 md:flex-row md:items-start md:justify-between"
+          >
+            <div class="min-w-0">
+              <div class="text-base font-semibold text-gray-900 dark:text-gray-100">
+                {{ usuario.Nome || usuario.Login || "Usuário sem nome" }}
+              </div>
+              <div class="mt-1 text-sm text-gray-500 dark:text-gray-400">
+                Login: {{ usuario.Login || "-" }}
+              </div>
+              <div class="mt-1 text-sm text-gray-500 dark:text-gray-400">
+                E-mail: {{ usuario.Email || "-" }}
+              </div>
+            </div>
+
+            <div class="flex flex-wrap gap-2">
+              <span
+                class="inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium"
+                :class="classeStatus(usuario.Status)"
+              >
+                {{ formatarStatus(usuario.Status) }}
+              </span>
+              <span
+                class="inline-flex items-center rounded-full border border-gray-200 bg-gray-100 px-2.5 py-1 text-xs font-medium text-gray-600 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300"
+              >
+                Nivel: {{ usuario.Nivel ?? "-" }}
+              </span>
+              <span
+                class="inline-flex items-center rounded-full border border-gray-200 bg-gray-100 px-2.5 py-1 text-xs font-medium text-gray-600 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300"
+              >
+                Setor: {{ usuario.Setor ?? "-" }}
+              </span>
+            </div>
+          </div>
+        </article>
+      </div>
+    </section>
+  </LayoutSistema>
+</template>