Files
html/generated/file_04.html
2026-04-12 22:57:03 +02:00

80 lines
4.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- front.html Vue3 CDN + Tailwind, 100 % côté client -->
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>WEVIA ERP</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-50">
<div id="app" class="min-h-screen flex flex-col">
<header class="bg-indigo-700 text-white p-4 shadow">
<h1 class="text-xl font-bold">WEVIA ERP</h1>
</header>
<main class="flex-grow container mx-auto p-4">
<div v-if="!token">
<form @submit.prevent="login" class="max-w-sm mx-auto bg-white p-6 rounded shadow">
<h2 class="mb-4 text-lg font-semibold">Connexion</h2>
<input v-model="formLogin.username" placeholder="email" class="w-full mb-3 px-3 py-2 border rounded">
<input v-model="formLogin.password" type="password" placeholder="mot de passe" class="w-full mb-3 px-3 py-2 border rounded">
<button class="w-full bg-indigo-600 text-white py-2 rounded">Se connecter</button>
</form>
</div>
<div v-else>
<button @click="logout" class="mb-4 text-sm text-indigo-700">Déconnexion</button>
<div class="grid gap-6 md:grid-cols-2">
<section class="bg-white p-4 rounded shadow">
<h2 class="mb-2 font-semibold">Produits</h2>
<ul>
<li v-for="p in products" :key="p.id" class="flex justify-between py-1">
<span>{{ p.name }}</span>
<span class="font-medium">{{ p.qty_in_stock }} u. {{ p.price }} €</span>
</li>
</ul>
</section>
<section class="bg-white p-4 rounded shadow">
<h2 class="mb-2 font-semibold">Nouvelle vente</h2>
<form @submit.prevent="createSale">
<input v-model.number="saleForm.customer_id" placeholder="ID client" class="w-full mb-2 px-3 py-2 border rounded">
<div v-for="(l,i) in saleForm.lines" :key="i" class="flex gap-2 mb-2">
<input v-model.number="l.product_id" placeholder="ID produit" class="w-1/3 px-3 py-2 border rounded">
<input v-model.number="l.qty" placeholder="Qté" class="w-1/3 px-3 py-2 border rounded">
<button type="button" @click="saleForm.lines.push({})" class="text-green-600">+</button>
<button type="button" @click="saleForm.lines.splice(i,1)" class="text-red-600"></button>
</div>
<button class="w-full bg-indigo-600 text-white py-2 rounded">Enregistrer</button>
</form>
</section>
</div>
</div>
</main>
</div>
<script>
const { createApp, reactive, ref, onMounted } = Vue;
createApp({
setup() {
const token = ref(localStorage.token||"");
const formLogin = reactive({username:"",password:""});
const products = ref([]);
const saleForm = reactive({customer_id:"",lines:[{product_id:"",qty:""}]});
const api = (path,opts={}) => fetch("http://localhost:8000/api/v1"+path,{headers:{Authorization:"Bearer "+token.value},...opts}).then(r=>r.ok?r.json():Promise.reject(r));
const login = async () => {
const body = new URLSearchParams({username:formLogin.username, password:formLogin.password});
const res = await fetch("http://localhost:8000/api/v1/token",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body});
const json = await res.json();
token.value = json.access_token;
localStorage.token = token.value;
loadProducts();
};
const logout = () => { token.value=""; localStorage.token=""; };
const loadProducts = () => api("/products").then(r => products.value = r);
const createSale = () => api("/sales",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(saleForm)})
.then(() => { alert("Vente créée"); loadProducts(); saleForm.lines=[{}]; });
onMounted(() => { if(token.value) loadProducts(); });
return { token, formLogin, login, logout, products, saleForm, createSale };
}
}).mount('#app');
</script>
</body>
</html>