Initial commit: ROA2WEB - FastAPI + Vue.js + Telegram Bot
Modern ERP Reports Application with microservices architecture Tech Stack: - Backend: FastAPI + python-oracledb (Oracle DB integration) - Frontend: Vue.js 3 + PrimeVue + Vite - Telegram Bot: python-telegram-bot + SQLite - Infrastructure: Shared database pool, JWT authentication, SSH tunnel Features: - FastAPI backend with async Oracle connection pool - Vue.js 3 responsive frontend with PrimeVue components - Telegram bot alternative interface - Microservices architecture with shared components - Complete deployment support (Linux Docker + Windows IIS) - Comprehensive testing (Playwright E2E + pytest) Repository Structure: - reports-app/ - Main application (backend, frontend, telegram-bot) - shared/ - Shared components (database pool, auth, utils) - deployment/ - Deployment scripts (Linux & Windows) - docs/ - Project documentation - security/ - Security scanning and git hooks
This commit is contained in:
221
reports-app/frontend/src/App.vue
Normal file
221
reports-app/frontend/src/App.vue
Normal file
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<!-- Navigation Bar -->
|
||||
<Menubar
|
||||
v-if="authStore.isAuthenticated"
|
||||
:model="menuItems"
|
||||
class="app-menubar"
|
||||
>
|
||||
<template #start>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-chart-bar text-primary text-2xl"></i>
|
||||
<span class="font-bold text-xl">ROA Reports</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #end>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<Badge
|
||||
:value="selectedCompany?.name || 'Selectați firmă'"
|
||||
:severity="selectedCompany ? 'info' : 'warning'"
|
||||
/>
|
||||
<Button
|
||||
icon="pi pi-sign-out"
|
||||
label="Deconectare"
|
||||
text
|
||||
@click="logout"
|
||||
class="p-button-text"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Menubar>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main
|
||||
class="main-content"
|
||||
:class="{ 'with-navbar': authStore.isAuthenticated }"
|
||||
>
|
||||
<router-view />
|
||||
</main>
|
||||
|
||||
<!-- Global Toast Messages - positioned below header to avoid covering company selector -->
|
||||
<Toast position="top-center" :style="{ top: '80px' }" />
|
||||
|
||||
<!-- Global Confirmation Dialog -->
|
||||
<ConfirmDialog />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useAuthStore } from "./stores/auth";
|
||||
import { useCompanyStore } from "./stores/companies";
|
||||
|
||||
const router = useRouter();
|
||||
const authStore = useAuthStore();
|
||||
const companyStore = useCompanyStore();
|
||||
|
||||
// Dashboard options
|
||||
const dashboardOptions = [
|
||||
{ label: 'Main Dashboard', value: '/dashboard' },
|
||||
{ label: 'New Dashboard', value: '/dashboard-new' },
|
||||
{ label: 'Ultra Minimal', value: '/dashboard-v1' },
|
||||
{ label: 'Compact Grid', value: '/dashboard-v2' },
|
||||
{ label: 'Data Tables', value: '/dashboard-v3' },
|
||||
{ label: 'Action Center', value: '/dashboard-v4' }
|
||||
];
|
||||
|
||||
// Menu items for navigation
|
||||
const menuItems = computed(() => [
|
||||
{
|
||||
label: "Dashboard",
|
||||
icon: "pi pi-home",
|
||||
items: dashboardOptions.map(option => ({
|
||||
label: option.label,
|
||||
command: () => router.push(option.value)
|
||||
}))
|
||||
},
|
||||
{
|
||||
label: "Facturi",
|
||||
icon: "pi pi-file-text",
|
||||
command: () => router.push("/invoices"),
|
||||
},
|
||||
{
|
||||
label: "Registru Casa si Banca",
|
||||
icon: "pi pi-wallet",
|
||||
command: () => router.push("/bank-cash-register"),
|
||||
},
|
||||
]);
|
||||
|
||||
// Get selected company
|
||||
const selectedCompany = computed(() => companyStore.selectedCompany);
|
||||
|
||||
// Logout function
|
||||
const logout = () => {
|
||||
authStore.logout();
|
||||
router.push("/login");
|
||||
};
|
||||
|
||||
// Initialize app
|
||||
onMounted(async () => {
|
||||
// Check authentication on app start
|
||||
if (authStore.isAuthenticated) {
|
||||
try {
|
||||
// Load companies if authenticated
|
||||
await companyStore.loadCompanies();
|
||||
} catch (error) {
|
||||
console.error("Failed to load companies:", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#app {
|
||||
min-height: 100vh;
|
||||
background-color: var(--surface-ground);
|
||||
}
|
||||
|
||||
.app-menubar {
|
||||
border-radius: 0;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.main-content.with-navbar {
|
||||
margin-top: 0;
|
||||
min-height: calc(100vh - 70px);
|
||||
}
|
||||
|
||||
.main-content:not(.with-navbar) {
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
/* Global styles */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family:
|
||||
"Inter",
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
Roboto,
|
||||
Oxygen,
|
||||
Ubuntu,
|
||||
Cantarell,
|
||||
sans-serif;
|
||||
background-color: var(--surface-ground);
|
||||
}
|
||||
|
||||
.app-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.app-container {
|
||||
padding: 0.25rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.app-menubar .p-menubar-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.main-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
padding: 0;
|
||||
max-width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom PrimeVue overrides */
|
||||
.p-button {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.p-datatable .p-datatable-tbody > tr.invoice-paid {
|
||||
background-color: var(--green-50);
|
||||
color: var(--green-900);
|
||||
}
|
||||
|
||||
.p-datatable .p-datatable-tbody > tr.invoice-overdue {
|
||||
background-color: var(--red-50);
|
||||
color: var(--red-900);
|
||||
}
|
||||
|
||||
/* Status badges */
|
||||
.status-paid {
|
||||
background-color: var(--green-100);
|
||||
color: var(--green-900);
|
||||
}
|
||||
|
||||
.status-overdue {
|
||||
background-color: var(--red-100);
|
||||
color: var(--red-900);
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: var(--yellow-100);
|
||||
color: var(--yellow-900);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user