Merge branch 'front_foundation' of https://gitea.piair.dev/piair/MyINPulse into front_foundation
This commit is contained in:
commit
7e0851bfef
@ -1,10 +1,63 @@
|
|||||||
{
|
{
|
||||||
"entrepreneurs": [
|
"entrepreneurs": [
|
||||||
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
|
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
|
||||||
{ "id": 2, "name": "Bob", "email": "bob@example.com" },
|
{ "id": 2, "name": "Bob", "email": "bob@example.com" },
|
||||||
{ "id": 3, "name": "Charlie", "email": "charlie@example.com" }
|
{ "id": 3, "name": "Charlie", "email": "charlie@example.com" }
|
||||||
],
|
],
|
||||||
"data": [
|
"data": [
|
||||||
{ "canva_data": "this is a fake data to test api" }
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 1,
|
||||||
|
"title_text": "1. Problème",
|
||||||
|
"description": "3 problèmes essentiels à résoudre pour le client"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 2,
|
||||||
|
"title_text": "2. Segments",
|
||||||
|
"description": "Les segments de clientèle visés"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 3,
|
||||||
|
"title_text": "3. Valeur",
|
||||||
|
"description": "La proposition de valeur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 4,
|
||||||
|
"title_text": "4. Solution",
|
||||||
|
"description": "Les solutions proposées"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 5,
|
||||||
|
"title_text": "5. Avantage",
|
||||||
|
"description": "Les avantages concurrentiels"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 6,
|
||||||
|
"title_text": "6. Canaux",
|
||||||
|
"description": "Les canaux de distribution"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 7,
|
||||||
|
"title_text": "7. Indicateurs",
|
||||||
|
"description": "Les indicateurs clés de performance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 8,
|
||||||
|
"title_text": "8. Coûts",
|
||||||
|
"description": "Les coûts associés"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": 1,
|
||||||
|
"title": 9,
|
||||||
|
"title_text": "9. Revenus",
|
||||||
|
"description": "Les sources de revenus"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
191
front/MyINPulse-front/src/components/canvas/CanvasItem.vue
Normal file → Executable file
191
front/MyINPulse-front/src/components/canvas/CanvasItem.vue
Normal file → Executable file
@ -1,21 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="['cell', { expanded }]" @click="handleClick">
|
<div :class="['cell', { expanded }]" @click="handleClick">
|
||||||
<h3>{{ title }}</h3>
|
<h3>{{ title_text }}</h3>
|
||||||
|
|
||||||
<!-- Mode affichage -->
|
<div v-for="(desc, index) in currentDescriptions" :key="index">
|
||||||
<template v-if="!isEditing">
|
<!-- Mode affichage -->
|
||||||
<p>{{ currentDescription }}</p>
|
<template v-if="!isEditing[index]">
|
||||||
<button v-if="expanded" @click.stop="startEditing" class="edit-button">Éditer</button>
|
<div class="description">
|
||||||
</template>
|
<p>{{ desc }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="button-container">
|
||||||
|
<button v-if="expanded" @click.stop="startEditing(index)" class="edit-button">Éditer</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Mode édition -->
|
||||||
|
<template v-else>
|
||||||
|
<textarea v-model="editedDescriptions[index]" class="edit-input"></textarea>
|
||||||
|
<div class="button-container">
|
||||||
|
<button @click.stop="saveEdit(index)" class="save-button">Enregistrer</button>
|
||||||
|
<button @click.stop="cancelEdit(index)" class="cancel-button">Annuler</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Mode édition -->
|
|
||||||
<template v-else>
|
|
||||||
<textarea v-model="editedDescription" class="edit-input"></textarea>
|
|
||||||
<div class="button-container">
|
|
||||||
<button @click.stop="saveEdit" class="save-button">Enregistrer</button>
|
|
||||||
<button @click.stop="cancelEdit" class="cancel-button">Annuler</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -23,16 +30,22 @@
|
|||||||
import { ref, defineProps } from "vue";
|
import { ref, defineProps } from "vue";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
const props = defineProps<{
|
const IS_MOCK_MODE = true;
|
||||||
title: string;
|
|
||||||
|
const props = defineProps<{
|
||||||
|
projectId: number;
|
||||||
|
title: number;
|
||||||
|
title_text: string;
|
||||||
description: string;
|
description: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const expanded = ref(false);
|
const expanded = ref(false);
|
||||||
const isEditing = ref(false);
|
const currentDescriptions = ref<string[]>([]);
|
||||||
const currentDescription = ref(props.description);
|
const editedDescriptions = ref<string[]>([]);
|
||||||
const editedDescription = ref(props.description);
|
const isEditing = ref<boolean[]>([]);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get("http://localhost:5000/data"); // Met à jour l'URL
|
const response = await axios.get("http://localhost:5000/data"); // Met à jour l'URL
|
||||||
@ -46,32 +59,121 @@ const fetchData = async () => {
|
|||||||
console.error("Erreur lors de la récupération des données :", error);
|
console.error("Erreur lors de la récupération des données :", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Fonction de simulation de l'API
|
||||||
|
const mockFetch = async (projectId: number, title: number, date: string) => {
|
||||||
|
console.log(`Mock fetch pour projectId: ${projectId}, title: ${title}, date: ${date}`);
|
||||||
|
|
||||||
|
return new Promise<{ txt: string }[]>((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve([
|
||||||
|
{ txt: "Ceci est une description 1 pour tester the damn front, Why are u still reading dumbass this is just some nonsense sentence XD" },
|
||||||
|
{ txt: "Ceci est une description 1 pour tester the damn front, Bruh are u still here?" },
|
||||||
|
{ txt: "Ceci est une description 1 pour tester the damn front, .-. BRUH" }
|
||||||
|
]);
|
||||||
|
}, 500); // Simule un délai réseau de 500ms
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fonction fetchData avec possibilité d'utiliser le mock
|
||||||
|
const fetchData = async (projectId: number, title: number, date: string, useMock = false) => {
|
||||||
|
try {
|
||||||
|
const responseData = useMock
|
||||||
|
? await mockFetch(projectId, title, date)
|
||||||
|
: (await axios.get<{ txt: string }[]>(
|
||||||
|
`http://localhost:5000/shared/projects/lcsection/${projectId}/${title}/${date}`
|
||||||
|
)).data;
|
||||||
|
|
||||||
|
if (responseData.length > 0) {
|
||||||
|
currentDescriptions.value = responseData.map((item) => item.txt);
|
||||||
|
editedDescriptions.value = [...currentDescriptions.value]; // Copie initiale
|
||||||
|
isEditing.value = Array(responseData.length).fill(false);
|
||||||
|
} else {
|
||||||
|
console.warn("Aucune donnée reçue.");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la récupération des données :", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Utilisation du mock dans handleClick pour tester sans serveur
|
||||||
const handleClick = async () => {
|
const handleClick = async () => {
|
||||||
if (!expanded.value) {
|
if (!expanded.value) {
|
||||||
await fetchData();
|
await fetchData(props.projectId, props.title, "NaN", IS_MOCK_MODE); // true pour activer le mock
|
||||||
} else if (!isEditing.value) {
|
} else if (!isEditing.value.includes(true)) {
|
||||||
currentDescription.value = props.description;
|
// Réinitialiser les descriptions si aucune édition n'est en cours
|
||||||
editedDescription.value = props.description;
|
currentDescriptions.value = [props.description];
|
||||||
|
editedDescriptions.value = [props.description];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEditing.value) {
|
if (!isEditing.value.includes(true)) {
|
||||||
expanded.value = !expanded.value;
|
expanded.value = !expanded.value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const startEditing = () => {
|
|
||||||
isEditing.value = true;
|
const startEditing = (index: number) => {
|
||||||
|
isEditing.value[index] = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveEdit = () => {
|
/*
|
||||||
currentDescription.value = editedDescription.value;
|
const saveEdit = async (index: number) => {
|
||||||
isEditing.value = false;
|
try {
|
||||||
|
const id = index + 1; // À adapter selon l'ID réel des données
|
||||||
|
await axios.put(`http://localhost:5000/data/${id}`, {
|
||||||
|
canva_data: editedDescriptions.value[index]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mettre à jour l'affichage local après la mise à jour réussie
|
||||||
|
currentDescriptions.value[index] = editedDescriptions.value[index];
|
||||||
|
isEditing.value[index] = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la mise à jour des données :", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Fonction de mock pour l'enregistrement
|
||||||
|
const mockSaveEdit = async (index: number) => {
|
||||||
|
try {
|
||||||
|
const id = index + 1; // À adapter selon l'ID réel des données
|
||||||
|
console.log(`Mock save pour l'ID ${id} avec la description : ${editedDescriptions.value[index]}`);
|
||||||
|
|
||||||
|
// Simuler un délai d'enregistrement comme une requête réseau
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 500)); // Simulation de délai réseau
|
||||||
|
|
||||||
|
// Mettre à jour l'affichage local après la mise à jour réussie
|
||||||
|
currentDescriptions.value[index] = editedDescriptions.value[index];
|
||||||
|
isEditing.value[index] = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la mise à jour des données mockées :", error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelEdit = () => {
|
// Utilisation de `mockSaveEdit` au lieu de `saveEdit` dans `handleClick` ou tout autre endroit
|
||||||
editedDescription.value = currentDescription.value;
|
const saveEdit = async (index: number) => {
|
||||||
isEditing.value = false;
|
if (IS_MOCK_MODE) {
|
||||||
|
await mockSaveEdit(index);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const id = index + 1;
|
||||||
|
await axios.put(`http://localhost:5000/data/${id}`, {
|
||||||
|
canva_data: editedDescriptions.value[index]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mettre à jour l'affichage local après la mise à jour réussie
|
||||||
|
currentDescriptions.value[index] = editedDescriptions.value[index];
|
||||||
|
isEditing.value[index] = false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la mise à jour des données :", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelEdit = (index: number) => {
|
||||||
|
editedDescriptions.value[index] = currentDescriptions.value[index];
|
||||||
|
isEditing.value[index] = false;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -109,6 +211,17 @@ const cancelEdit = () => {
|
|||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cell .description {
|
||||||
|
width: 800px;
|
||||||
|
height: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.expanded {
|
.expanded {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -124,21 +237,21 @@ const cancelEdit = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.edit-input {
|
.edit-input {
|
||||||
width: 80%;
|
width: 800px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.button-container {
|
.button-container {
|
||||||
position: absolute;
|
|
||||||
bottom: 20px;
|
|
||||||
right: 20px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-button, .save-button, .cancel-button {
|
.edit-button, .save-button, .cancel-button {
|
||||||
@ -147,7 +260,8 @@ const cancelEdit = () => {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background 0.3s ease;
|
transition: background 0.3s ease;
|
||||||
font-size: 16px;
|
font-size: 12px;
|
||||||
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-button {
|
.edit-button {
|
||||||
@ -177,5 +291,4 @@ const cancelEdit = () => {
|
|||||||
background-color: #c82333;
|
background-color: #c82333;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -4,7 +4,9 @@
|
|||||||
v-for="(item, index) in items"
|
v-for="(item, index) in items"
|
||||||
:key="index"
|
:key="index"
|
||||||
:title="item.title"
|
:title="item.title"
|
||||||
|
:title_text="item.title_text"
|
||||||
:description="item.description"
|
:description="item.description"
|
||||||
|
:projectId="item.projectId"
|
||||||
:class="item.class"
|
:class="item.class"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -15,16 +17,17 @@ import { ref } from "vue";
|
|||||||
import CanvasItem from "@/components/canvas/CanvasItem.vue";
|
import CanvasItem from "@/components/canvas/CanvasItem.vue";
|
||||||
|
|
||||||
const items = ref([
|
const items = ref([
|
||||||
{ title: "1. Problème", description: "3 problèmes essentiels à résoudre pour le client", class: "Probleme" },
|
{ projectId: 1, title: 1, title_text: "1. Problème", description: "3 problèmes essentiels à résoudre pour le client", class: "Probleme" },
|
||||||
{ title: "2. Segments", description: "Les segments de clientèle visés", class: "Segments" },
|
{ projectId: 1, title: 2, title_text: "2. Segments", description: "Les segments de clientèle visés", class: "Segments" },
|
||||||
{ title: "3. Valeur", description: "La proposition de valeur", class: "Valeur" },
|
{ projectId: 1, title: 3, title_text: "3. Valeur", description: "La proposition de valeur", class: "Valeur" },
|
||||||
{ title: "4. Solution", description: "Les solutions proposées", class: "Solution" },
|
{ projectId: 1, title: 4, title_text: "4. Solution", description: "Les solutions proposées", class: "Solution" },
|
||||||
{ title: "5. Avantage", description: "Les avantages concurrentiels", class: "Avantage" },
|
{ projectId: 1, title: 5, title_text: "5. Avantage", description: "Les avantages concurrentiels", class: "Avantage" },
|
||||||
{ title: "6. Canaux", description: "Les canaux de distribution", class: "Canaux" },
|
{ projectId: 1, title: 6, title_text: "6. Canaux", description: "Les canaux de distribution", class: "Canaux" },
|
||||||
{ title: "7. Indicateurs", description: "Les indicateurs clés de performance", class: "Indicateurs" },
|
{ projectId: 1, title: 7, title_text: "7. Indicateurs", description: "Les indicateurs clés de performance", class: "Indicateurs" },
|
||||||
{ title: "8. Coûts", description: "Les coûts associés", class: "Couts" },
|
{ projectId: 1, title: 8, title_text: "8. Coûts", description: "Les coûts associés", class: "Couts" },
|
||||||
{ title: "9. Revenus", description: "Les sources de revenus", class: "Revenus" }
|
{ projectId: 1, title: 9, title_text: "9. Revenus", description: "Les sources de revenus", class: "Revenus" }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user