Frontend (v1.0.95)

Ordenamiento consistente de preguntas (App.jsx):

Las preguntas ahora se ordenan por el campo order antes de agruparse por sección
Esto asegura que el orden se mantenga exactamente como está en el backend
Ordenamiento de secciones (App.jsx):

Las secciones se ordenan por el order mínimo de sus preguntas
Garantiza que las secciones aparezcan en orden lógico y consistente
Mejora en drag-and-drop (App.jsx):

Al reordenar, ahora se ordenan las preguntas por order antes de calcular nuevas posiciones
Los nuevos valores de order se asignan correctamente preservando el orden relativo
Funciona correctamente con una sola sección y con subpreguntas
Ordenamiento en modo inspección (App.jsx):

getVisibleQuestions() ahora ordena las preguntas visibles por su campo order
Mantiene el orden correcto durante la ejecución de inspecciones
Backend (v1.0.92)
No se requirieron cambios en el backend (ya estaba ordenando correctamente con order_by(models.Question.order))
This commit is contained in:
2025-12-02 15:50:22 -03:00
parent 7f50bfd8c6
commit de5f09a351
4 changed files with 34 additions and 19 deletions

View File

@@ -209,7 +209,7 @@ def send_completed_inspection_to_n8n(inspection, db):
# No lanzamos excepción para no interrumpir el flujo normal # No lanzamos excepción para no interrumpir el flujo normal
BACKEND_VERSION = "1.0.91" BACKEND_VERSION = "1.0.92"
app = FastAPI(title="Checklist Inteligente API", version=BACKEND_VERSION) app = FastAPI(title="Checklist Inteligente API", version=BACKEND_VERSION)
# S3/MinIO configuration # S3/MinIO configuration

View File

@@ -1,7 +1,7 @@
{ {
"name": "checklist-frontend", "name": "checklist-frontend",
"private": true, "private": true,
"version": "1.0.94", "version": "1.0.95",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -1,6 +1,6 @@
// Service Worker para PWA con detección de actualizaciones // Service Worker para PWA con detección de actualizaciones
// IMPORTANTE: Actualizar esta versión cada vez que se despliegue una nueva versión // IMPORTANTE: Actualizar esta versión cada vez que se despliegue una nueva versión
const CACHE_NAME = 'ayutec-v1.0.94'; const CACHE_NAME = 'ayutec-v1.0.95';
const urlsToCache = [ const urlsToCache = [
'/', '/',
'/index.html' '/index.html'

View File

@@ -1459,10 +1459,11 @@ function QuestionsManagerModal({ checklist, onClose }) {
// Solo subpreguntas del mismo padre // Solo subpreguntas del mismo padre
questionsList = questions.filter(q => questionsList = questions.filter(q =>
q.parent_question_id === draggedQuestion.parent_question_id q.parent_question_id === draggedQuestion.parent_question_id
) ).sort((a, b) => a.order - b.order) // Ordenar por order actual
} else { } else {
// Solo preguntas padre (sin parent_question_id) // Solo preguntas padre (sin parent_question_id)
questionsList = questions.filter(q => !q.parent_question_id) questionsList = questions.filter(q => !q.parent_question_id)
.sort((a, b) => a.order - b.order) // Ordenar por order actual
} }
const draggedIndex = questionsList.findIndex(q => q.id === draggedQuestion.id) const draggedIndex = questionsList.findIndex(q => q.id === draggedQuestion.id)
@@ -1473,10 +1474,11 @@ function QuestionsManagerModal({ checklist, onClose }) {
const [movedQuestion] = newList.splice(draggedIndex, 1) const [movedQuestion] = newList.splice(draggedIndex, 1)
newList.splice(targetIndex, 0, movedQuestion) newList.splice(targetIndex, 0, movedQuestion)
// Preparar datos para el backend (solo las preguntas afectadas) // Preparar datos para el backend usando los valores de 'order' originales
// Esto mantiene el orden relativo correcto con respecto a otras preguntas
const reorderData = newList.map((q, index) => ({ const reorderData = newList.map((q, index) => ({
question_id: q.id, question_id: q.id,
new_order: index new_order: questionsList[index].order // Usar el order de la posición correspondiente
})) }))
try { try {
@@ -1506,7 +1508,11 @@ function QuestionsManagerModal({ checklist, onClose }) {
setDragOverQuestion(null) setDragOverQuestion(null)
} }
const questionsBySection = questions.reduce((acc, q) => { // Primero ordenar todas las preguntas por el campo 'order' para mantener el orden del backend
const sortedQuestions = [...questions].sort((a, b) => a.order - b.order)
// Luego agrupar por sección manteniendo el orden
const questionsBySection = sortedQuestions.reduce((acc, q) => {
const section = q.section || 'Sin sección' const section = q.section || 'Sin sección'
if (!acc[section]) acc[section] = [] if (!acc[section]) acc[section] = []
acc[section].push(q) acc[section].push(q)
@@ -1867,7 +1873,14 @@ function QuestionsManagerModal({ checklist, onClose }) {
</div> </div>
) : ( ) : (
<div className="space-y-6"> <div className="space-y-6">
{Object.entries(questionsBySection).map(([section, sectionQuestions]) => ( {Object.entries(questionsBySection)
.sort(([, questionsA], [, questionsB]) => {
// Ordenar secciones por el 'order' mínimo de sus preguntas
const minOrderA = Math.min(...questionsA.map(q => q.order))
const minOrderB = Math.min(...questionsB.map(q => q.order))
return minOrderA - minOrderB
})
.map(([section, sectionQuestions]) => (
<div key={section} className="border border-gray-200 rounded-lg overflow-hidden"> <div key={section} className="border border-gray-200 rounded-lg overflow-hidden">
<div className="bg-gray-100 px-4 py-3"> <div className="bg-gray-100 px-4 py-3">
<h3 className="font-semibold text-gray-900">{section}</h3> <h3 className="font-semibold text-gray-900">{section}</h3>
@@ -4333,17 +4346,19 @@ function InspectionModal({ checklist, existingInspection, user, onClose, onCompl
// Get visible questions based on conditional logic // Get visible questions based on conditional logic
const getVisibleQuestions = () => { const getVisibleQuestions = () => {
return questions.filter(q => { return questions
// If no parent, always visible .filter(q => {
if (!q.parent_question_id) return true // If no parent, always visible
if (!q.parent_question_id) return true
// Check parent answer
const parentAnswer = answers[q.parent_question_id] // Check parent answer
if (!parentAnswer) return false const parentAnswer = answers[q.parent_question_id]
if (!parentAnswer) return false
// Show if parent answer matches trigger
return parentAnswer.value === q.show_if_answer // Show if parent answer matches trigger
}) return parentAnswer.value === q.show_if_answer
})
.sort((a, b) => a.order - b.order) // Mantener orden del backend
} }
// Move to signatures step // Move to signatures step