Files
josedario87 955584275b fix: Corregir configuración de estilos y componentes
- Agregar imports de Tailwind CSS v4 y Nuxt UI en main.css
- Renombrar QueueActions.vue -> Actions.vue y QueueItem.vue -> Item.vue para evitar conflictos de nombres de componentes
- Crear composable useMediaQuery para manejo de responsive
- Corregir referencias a componentes en index.vue y PrintQueue.vue
- Actualizar imports de servidor a rutas relativas
- Instalar @iconify-json/heroicons y @iconify-json/lucide
- Actualizar Jimp a sintaxis v1.x
2025-11-24 18:27:29 -06:00

184 lines
5.2 KiB
Vue

<script setup lang="ts">
import type { Operation } from '~/composables/usePrintQueue'
const props = defineProps<{
operation: Operation
index: number
isFirst: boolean
isLast: boolean
}>()
const emit = defineEmits<{
update: [op: Operation]
remove: []
'move-up': []
'move-down': []
}>()
const isEditing = ref(false)
const editableFields = reactive<Record<string, string>>({})
// Color según tipo de operación
const opColor = computed(() => {
const op = props.operation.op
if (op.startsWith('text')) return 'primary'
if (op.startsWith('feed')) return 'info'
if (op === 'cut') return 'warning'
if (op === 'pulse') return 'success'
if (op === 'barcode' || op === 'qrcode') return 'secondary'
return 'neutral'
})
// Icono según tipo de operación
const opIcon = computed(() => {
const op = props.operation.op
if (op === 'text') return 'i-heroicons-document-text'
if (op.startsWith('text')) return 'i-heroicons-adjustments-horizontal'
if (op.startsWith('feed')) return 'i-heroicons-arrow-down'
if (op === 'cut') return 'i-heroicons-scissors'
if (op === 'pulse') return 'i-heroicons-bolt'
if (op === 'barcode') return 'i-heroicons-bars-3'
if (op === 'qrcode') return 'i-heroicons-qr-code'
return 'i-heroicons-cog-6-tooth'
})
// Inicializar campos editables
function initEditableFields() {
Object.keys(editableFields).forEach(k => delete editableFields[k])
for (const [k, v] of Object.entries(props.operation)) {
if (k === 'op') continue
editableFields[k] = typeof v === 'object' ? JSON.stringify(v) : String(v)
}
}
watch(() => props.operation, initEditableFields, { immediate: true, deep: true })
function applyChanges() {
const updated: Operation = { op: props.operation.op }
for (const [k, v] of Object.entries(editableFields)) {
try {
updated[k] = JSON.parse(v)
} catch {
const n = Number(v)
updated[k] = isNaN(n) ? v : n
}
}
emit('update', updated)
isEditing.value = false
}
function cancelEdit() {
initEditableFields()
isEditing.value = false
}
// Resumen legible del comando
const summary = computed(() => {
const op = props.operation
switch (op.op) {
case 'text':
return op.value?.substring(0, 30) + (op.value?.length > 30 ? '...' : '')
case 'textAlign':
return `Alinear: ${op.align}`
case 'textFont':
return `Fuente: ${op.font}`
case 'textSize':
return `Tamaño: ${op.width || 1}x${op.height || 1}`
case 'textStyle':
const styles = []
if (op.em) styles.push('negrita')
if (op.ul) styles.push('subrayado')
if (op.reverse) styles.push('invertido')
return styles.length ? `Estilo: ${styles.join(', ')}` : 'Estilo: normal'
case 'feedLine':
return `Feed: ${op.line} líneas`
case 'cut':
return `Cortar: ${op.type}`
case 'pulse':
return `Pulse: ${op.drawer}`
case 'qrcode':
return `QR: ${op.data?.substring(0, 20)}...`
case 'barcode':
return `Barcode: ${op.data}`
default:
return op.op
}
})
</script>
<template>
<UCard variant="soft" class="group">
<div class="flex items-start gap-3">
<!-- Indicador de tipo -->
<div class="flex flex-col items-center gap-1">
<UBadge :color="opColor" variant="subtle" size="xs">
{{ index + 1 }}
</UBadge>
<UIcon :name="opIcon" class="w-4 h-4 text-gray-400" />
</div>
<!-- Contenido -->
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-1">
<span class="font-medium text-sm text-gray-900 dark:text-white">
{{ operation.op }}
</span>
</div>
<!-- Vista normal -->
<p v-if="!isEditing" class="text-sm text-gray-500 dark:text-gray-400 truncate">
{{ summary }}
</p>
<!-- Vista edición -->
<div v-else class="space-y-2 mt-2">
<div v-for="(value, key) in editableFields" :key="key" class="flex items-center gap-2">
<span class="text-xs text-gray-500 w-16 shrink-0">{{ key }}:</span>
<UInput
v-model="editableFields[key]"
size="xs"
class="flex-1"
/>
</div>
<div class="flex gap-2 mt-2">
<UButton size="xs" @click="applyChanges">Aplicar</UButton>
<UButton size="xs" variant="ghost" @click="cancelEdit">Cancelar</UButton>
</div>
</div>
</div>
<!-- Acciones -->
<div class="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
<UButton
v-if="!isEditing"
icon="i-heroicons-pencil"
variant="ghost"
size="xs"
@click="isEditing = true"
/>
<UButton
icon="i-heroicons-chevron-up"
variant="ghost"
size="xs"
:disabled="isFirst"
@click="$emit('move-up')"
/>
<UButton
icon="i-heroicons-chevron-down"
variant="ghost"
size="xs"
:disabled="isLast"
@click="$emit('move-down')"
/>
<UButton
icon="i-heroicons-trash"
variant="ghost"
size="xs"
color="error"
@click="$emit('remove')"
/>
</div>
</div>
</UCard>
</template>