feat: ramène à la vue d'où l'on vient une fois le document enregistré
Éditer une ligne depuis Dépenses ou Recettes ouvrait le document, puis relâchait sur la liste des documents : il fallait revenir à la page d'analyse et refaire ses filtres à la main pour corriger la ligne suivante. Les deux tables passent maintenant à l'éditeur la vue d'où l'on part, filtres compris, et il y ramène à ses trois sorties : enregistrement terminé, abandon, et document introuvable. Sans cette destination — depuis la liste des documents, ou un lien direct — le repli reste la liste. La destination arrive par l'URL, donc fabricable par n'importe qui : seule une page de l'application est suivie (utils/retour.js). Une URL absolue, un chemin protocol-relatif que le navigateur lirait comme un domaine, ou des contre-slashs retombent sur le repli. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -84,7 +84,7 @@
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<router-link
|
||||
:to="{ path: '/documents/' + dep.document_id + '/edit', query: { highlight: 'operation', fournisseur: dep.fournisseur, description: dep.description } }"
|
||||
:to="lienEdition(dep)"
|
||||
class="text-gray-500 hover:text-blue-400 transition-colors"
|
||||
title="Editer le document source"
|
||||
>
|
||||
@@ -142,6 +142,9 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const props = defineProps({
|
||||
depenses: {
|
||||
@@ -169,6 +172,20 @@ const paginatedDepenses = computed(() =>
|
||||
props.depenses.slice(startIndex.value, endIndex.value)
|
||||
)
|
||||
|
||||
/** L'editeur recoit la vue d'ou l'on part, filtres compris : une fois
|
||||
l'enregistrement termine, il y ramene au lieu de la liste des documents. */
|
||||
function lienEdition(depense) {
|
||||
return {
|
||||
path: `/documents/${depense.document_id}/edit`,
|
||||
query: {
|
||||
highlight: 'operation',
|
||||
fournisseur: depense.fournisseur,
|
||||
description: depense.description,
|
||||
retour: route.fullPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(dateStr) {
|
||||
if (!dateStr) return '-'
|
||||
const d = new Date(dateStr)
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<router-link
|
||||
:to="{ path: '/documents/' + revenu.document_id + '/edit', query: { highlight: 'locataire', lot_numero: revenu.lot_numero, locataire_nom: revenu.locataire_nom } }"
|
||||
:to="lienEdition(revenu)"
|
||||
class="text-gray-500 hover:text-blue-400 transition-colors"
|
||||
title="Editer le document source"
|
||||
>
|
||||
@@ -140,6 +140,23 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
/** L'editeur recoit la vue d'ou l'on part, filtres compris : une fois
|
||||
l'enregistrement termine, il y ramene au lieu de la liste des documents. */
|
||||
function lienEdition(revenu) {
|
||||
return {
|
||||
path: `/documents/${revenu.document_id}/edit`,
|
||||
query: {
|
||||
highlight: 'locataire',
|
||||
lot_numero: revenu.lot_numero,
|
||||
locataire_nom: revenu.locataire_nom,
|
||||
retour: route.fullPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
revenus: {
|
||||
|
||||
@@ -151,6 +151,7 @@ import JsonViewer from '../components/JsonViewer.vue'
|
||||
import TaggingStep from '../components/TaggingStep.vue'
|
||||
import ReExtractionDiff from '../components/ReExtractionDiff.vue'
|
||||
import { computeExtractionDiff } from '../utils/diffExtraction.js'
|
||||
import { cheminRetour } from '../utils/retour.js'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
@@ -167,6 +168,10 @@ const reExtractError = ref(null)
|
||||
const diff = ref(null)
|
||||
const previousData = ref(null)
|
||||
|
||||
// D'ou l'on vient, et donc ou repartir une fois l'edition terminee : la table
|
||||
// d'analyse avec ses filtres si elle l'a dit, la liste des documents sinon.
|
||||
const destinationRetour = computed(() => cheminRetour(route.query.retour, '/documents'))
|
||||
|
||||
const highlightInfo = computed(() => {
|
||||
const q = route.query
|
||||
if (q.highlight === 'locataire') return { type: 'locataire', lot_numero: q.lot_numero, locataire_nom: q.locataire_nom }
|
||||
@@ -196,7 +201,7 @@ async function loadDocument() {
|
||||
} catch (err) {
|
||||
console.error('Error loading document:', err)
|
||||
alert('Erreur lors du chargement du document: ' + err.message)
|
||||
router.push('/documents')
|
||||
router.push(destinationRetour.value)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
@@ -214,7 +219,7 @@ function cancel() {
|
||||
const confirmed = confirm('Abandonner les modifications ?')
|
||||
if (!confirmed) return
|
||||
}
|
||||
router.push('/documents')
|
||||
router.push(destinationRetour.value)
|
||||
}
|
||||
|
||||
function goToTagging() {
|
||||
@@ -284,7 +289,7 @@ async function handleSave(depensesTags, shouldOverwrite) {
|
||||
|
||||
if (result.success) {
|
||||
// Succès - redirection vers la liste des documents
|
||||
router.push('/documents')
|
||||
router.push(destinationRetour.value)
|
||||
} else {
|
||||
throw new Error(result.message || 'Échec de la sauvegarde')
|
||||
}
|
||||
|
||||
22
frontend/src/utils/retour.js
Normal file
22
frontend/src/utils/retour.js
Normal file
@@ -0,0 +1,22 @@
|
||||
// Une table d'analyse envoie vers l'editeur de document la page ou revenir une
|
||||
// fois l'enregistrement termine, filtres compris. Cette destination arrive par
|
||||
// l'URL : elle est donc fabricable par n'importe qui, et n'est suivie que si
|
||||
// elle designe une page de l'application.
|
||||
|
||||
/**
|
||||
* La destination de retour portee par une query, ou `repli` si elle manque ou
|
||||
* ne designe pas un chemin interne.
|
||||
*
|
||||
* Sont refuses tout ce qui peut sortir du site : une URL absolue
|
||||
* (`https://ailleurs`), un chemin protocol-relatif (`//ailleurs`) que le
|
||||
* navigateur traite comme un domaine, et les contre-slashs dont certains
|
||||
* navigateurs font des slashs.
|
||||
*/
|
||||
export function cheminRetour(brut, repli = '/documents') {
|
||||
const valeur = Array.isArray(brut) ? brut[0] : brut
|
||||
if (typeof valeur !== 'string' || valeur === '') return repli
|
||||
if (!valeur.startsWith('/')) return repli
|
||||
if (valeur.startsWith('//')) return repli
|
||||
if (valeur.includes('\\')) return repli
|
||||
return valeur
|
||||
}
|
||||
Reference in New Issue
Block a user