Compare commits
1 Commits
173cf3771b
...
enviar_ven
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b817ffc9fb |
2488
package-lock.json
generated
2488
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdi/font": "7.4.47",
|
"@mdi/font": "7.4.47",
|
||||||
"axios": "^1.13.5",
|
|
||||||
"core-js": "^3.37.1",
|
"core-js": "^3.37.1",
|
||||||
"roboto-fontface": "*",
|
"roboto-fontface": "*",
|
||||||
"vee-validate": "^4.14.6",
|
"vee-validate": "^4.14.6",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
required
|
required
|
||||||
class="mr-4"
|
class="mr-4"
|
||||||
></v-autocomplete>
|
></v-autocomplete>
|
||||||
<!-- <v-btn color="primary" @click="openModal">Agregar Cliente</v-btn> -->
|
<v-btn color="primary" @click="openModal">Agregar Cliente</v-btn>
|
||||||
<CreateCustomerModal ref="customerModal" @customerCreated="handleNewCustomer"/>
|
<CreateCustomerModal ref="customerModal" @customerCreated="handleNewCustomer"/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col lg="4">
|
<v-col lg="4">
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import AuthService from '@/services/auth';
|
|
||||||
import { inject } from 'vue';
|
|
||||||
|
|
||||||
const username = ref('');
|
|
||||||
const password = ref('');
|
|
||||||
const error = ref('');
|
|
||||||
|
|
||||||
async function login() {
|
|
||||||
try {
|
|
||||||
await AuthService.login({ username: username.value, password: password.value });
|
|
||||||
// opcional: redirigir al dashboard
|
|
||||||
} catch (e) {
|
|
||||||
error.value = e.message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ejemplo de llamada a clientes (requiere token)
|
|
||||||
const api = inject('api');
|
|
||||||
|
|
||||||
async function loadCustomers() {
|
|
||||||
try {
|
|
||||||
const data = await api.getCustomers();
|
|
||||||
console.log(data);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<h1>Login</h1>
|
|
||||||
<v-form @submit.prevent="login">
|
|
||||||
<v-text-field v-model="username" label="Usuario" required />
|
|
||||||
<v-text-field v-model="password" label="Contraseña" type="password" required />
|
|
||||||
<v-btn type="submit">Entrar</v-btn>
|
|
||||||
<v-alert v-if="error" type="error">{{ error }}</v-alert>
|
|
||||||
</v-form>
|
|
||||||
|
|
||||||
<v-btn @click="loadCustomers">Cargar clientes</v-btn>
|
|
||||||
</template>
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
required
|
required
|
||||||
class="mr-4"
|
class="mr-4"
|
||||||
></v-autocomplete>
|
></v-autocomplete>
|
||||||
<!--<v-btn color="primary" @click="openModal">Agregar Cliente</v-btn>-->
|
<v-btn color="primary" @click="openModal">Agregar Cliente</v-btn>
|
||||||
<CreateCustomerModal ref="customerModal" @customerCreated="handleNewCustomer"/>
|
<CreateCustomerModal ref="customerModal" @customerCreated="handleNewCustomer"/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col lg="4">
|
<v-col lg="4">
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
<template>
|
|
||||||
<Login />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
//
|
|
||||||
</script>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<template>
|
|
||||||
<Login />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
//
|
|
||||||
</script>
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
class AuthService {
|
|
||||||
static TOKEN_KEY = 'access_token';
|
|
||||||
static REFRESH_KEY = 'refresh_token';
|
|
||||||
|
|
||||||
static login(credentials) {
|
|
||||||
const url = `${import.meta.env.VITE_DJANGO_BASE_URL}/api/token/`;
|
|
||||||
return fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify(credentials),
|
|
||||||
})
|
|
||||||
.then(r => r.json())
|
|
||||||
.then(data => {
|
|
||||||
localStorage.setItem(this.TOKEN_KEY, data.access);
|
|
||||||
localStorage.setItem(this.REFRESH_KEY, data.refresh);
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static getAccessToken() {
|
|
||||||
return localStorage.getItem(this.TOKEN_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static getRefreshToken() {
|
|
||||||
return localStorage.getItem(this.REFRESH_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static async refresh() {
|
|
||||||
const refresh = this.getRefreshToken();
|
|
||||||
if (!refresh) throw new Error('No refresh token');
|
|
||||||
|
|
||||||
const url = `${import.meta.env.VITE_DJANGO_BASE_URL}/api/token/refresh/`;
|
|
||||||
const resp = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ refresh }),
|
|
||||||
});
|
|
||||||
const data = await resp.json();
|
|
||||||
localStorage.setItem(this.TOKEN_KEY, data.access);
|
|
||||||
return data.access;
|
|
||||||
}
|
|
||||||
|
|
||||||
static logout() {
|
|
||||||
localStorage.removeItem(this.TOKEN_KEY);
|
|
||||||
localStorage.removeItem(this.REFRESH_KEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AuthService;
|
|
||||||
@@ -1,38 +1,8 @@
|
|||||||
import AuthService from '@/services/auth';
|
|
||||||
|
|
||||||
class DjangoApi {
|
class DjangoApi {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.base = import.meta.env.VITE_DJANGO_BASE_URL;
|
this.base = import.meta.env.VITE_DJANGO_BASE_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
_authHeaders() {
|
|
||||||
const token = AuthService.getAccessToken();
|
|
||||||
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
||||||
}
|
|
||||||
|
|
||||||
_handleResponse(response) {
|
|
||||||
if (!response.ok) {
|
|
||||||
// Si el token ha expirado (401) intentamos refrescar y re‑intentar
|
|
||||||
if (response.status === 401) {
|
|
||||||
return AuthService.refresh().then(newToken => {
|
|
||||||
// volver a ejecutar la petición original con el nuevo token
|
|
||||||
const retryHeaders = {
|
|
||||||
...response.headers,
|
|
||||||
Authorization: `Bearer ${newToken}`,
|
|
||||||
};
|
|
||||||
// aquí usamos fetch de nuevo con los mismos parámetros
|
|
||||||
// (para simplificar, delegamos a getRequest/postRequest)
|
|
||||||
// En la práctica, extrae la lógica a una función reutilizable.
|
|
||||||
throw new Error('Retry logic should be implemented here');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return response.json().then(err => {
|
|
||||||
throw new Error(`Error ${response.status}: ${err.detail || response.statusText}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
getCustomers() {
|
getCustomers() {
|
||||||
const url = this.base + '/don_confiao/api/customers/';
|
const url = this.base + '/don_confiao/api/customers/';
|
||||||
return this.getRequest(url);
|
return this.getRequest(url);
|
||||||
@@ -109,23 +79,42 @@ class DjangoApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getRequest(url) {
|
getRequest(url) {
|
||||||
return fetch(url, {
|
return new Promise ((resolve, reject) => {
|
||||||
headers: {
|
fetch(url)
|
||||||
'Content-Type': 'application/json',
|
.then(response => response.json())
|
||||||
...this._authHeaders(),
|
.then(data => {
|
||||||
},
|
resolve(data);
|
||||||
}).then(this._handleResponse);
|
})
|
||||||
|
.catch(error => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
postRequest(url, content) {
|
postRequest(url, content) {
|
||||||
return fetch(url, {
|
return new Promise((resolve, reject) => {
|
||||||
method: 'POST',
|
fetch(url, {
|
||||||
headers: {
|
method: 'POST',
|
||||||
'Content-Type': 'application/json',
|
headers: {
|
||||||
...this._authHeaders(),
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(content),
|
body: JSON.stringify(content)
|
||||||
}).then(this._handleResponse);
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
reject(new Error(`Error ${response.status}: ${response.statusText}`));
|
||||||
|
} else {
|
||||||
|
response.json().then(data => {
|
||||||
|
if (!data) {
|
||||||
|
reject(new Error('La respuesta no es un JSON válido'));
|
||||||
|
} else {
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => reject(error));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,6 @@ import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
|
|||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import { fileURLToPath, URL } from 'node:url'
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
|
||||||
const aliasMap = {
|
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('🔧 Alias configurado:');
|
|
||||||
console.log(aliasMap); // <-- se muestra en la terminal al iniciar Vite
|
|
||||||
console.log('Resolución real de "@":', aliasMap['@']);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
@@ -60,7 +50,7 @@ export default defineConfig({
|
|||||||
} },
|
} },
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||||
},
|
},
|
||||||
extensions: [
|
extensions: [
|
||||||
'.js',
|
'.js',
|
||||||
|
|||||||
Reference in New Issue
Block a user