feat: Sistema de gestión de impresoras persistente

- Crear modelo Printer con campos: id, name, host, deviceId, timeout, isDefault
- Almacenamiento persistente en data/printers.json
- APIs CRUD: GET/POST /api/printers, GET/PUT/DELETE /api/printers/:id
- API para seleccionar impresora activa: POST /api/printers/select
- Endpoint de impresión ahora usa la impresora seleccionada o la especificada por printerId
- Composable usePrinters() para el cliente
- UI: Selector de impresora en sidebar, tab Impresoras en mobile
- Componentes: PrintersList, PrintersCard, PrintersForm, PrintersSelector
This commit is contained in:
2025-11-25 00:44:50 -06:00
parent 955584275b
commit e97b2b4d8e
15 changed files with 1006 additions and 6 deletions

View File

@@ -0,0 +1,203 @@
// Composable para gestión de impresoras
export interface Printer {
id: string
name: string
host: string
deviceId: string
timeout: number
isDefault: boolean
createdAt: string
updatedAt: string
}
const printers = ref<Printer[]>([])
const selectedPrinterId = ref<string | null>(null)
const loading = ref(false)
const error = ref<string | null>(null)
export function usePrinters() {
const selectedPrinter = computed(() =>
printers.value.find(p => p.id === selectedPrinterId.value) || null
)
const defaultPrinter = computed(() =>
printers.value.find(p => p.isDefault) || printers.value[0] || null
)
async function fetchPrinters() {
loading.value = true
error.value = null
try {
const response = await $fetch<{
ok: boolean
printers: Printer[]
selectedPrinterId: string | null
error?: string
}>('/api/printers')
if (response.ok) {
printers.value = response.printers
selectedPrinterId.value = response.selectedPrinterId
} else {
error.value = response.error || 'Error al cargar impresoras'
}
} catch (err: any) {
error.value = err.message
} finally {
loading.value = false
}
}
async function createPrinter(data: {
name: string
host: string
deviceId: string
timeout?: number
isDefault?: boolean
}) {
loading.value = true
error.value = null
try {
const response = await $fetch<{
ok: boolean
printer?: Printer
error?: string
}>('/api/printers', {
method: 'POST',
body: data
})
if (response.ok && response.printer) {
printers.value.push(response.printer)
// Si es la primera impresora, seleccionarla
if (printers.value.length === 1) {
selectedPrinterId.value = response.printer.id
}
return response.printer
} else {
error.value = response.error || 'Error al crear impresora'
return null
}
} catch (err: any) {
error.value = err.message
return null
} finally {
loading.value = false
}
}
async function updatePrinter(id: string, data: Partial<{
name: string
host: string
deviceId: string
timeout: number
isDefault: boolean
}>) {
loading.value = true
error.value = null
try {
const response = await $fetch<{
ok: boolean
printer?: Printer
error?: string
}>(`/api/printers/${id}`, {
method: 'PUT',
body: data
})
if (response.ok && response.printer) {
const index = printers.value.findIndex(p => p.id === id)
if (index !== -1) {
// Si se estableció como default, quitar default de las demás
if (data.isDefault) {
printers.value.forEach(p => p.isDefault = false)
}
printers.value[index] = response.printer
}
return response.printer
} else {
error.value = response.error || 'Error al actualizar impresora'
return null
}
} catch (err: any) {
error.value = err.message
return null
} finally {
loading.value = false
}
}
async function deletePrinter(id: string) {
loading.value = true
error.value = null
try {
const response = await $fetch<{
ok: boolean
error?: string
}>(`/api/printers/${id}`, {
method: 'DELETE'
})
if (response.ok) {
const index = printers.value.findIndex(p => p.id === id)
if (index !== -1) {
printers.value.splice(index, 1)
}
// Si era la seleccionada, seleccionar otra
if (selectedPrinterId.value === id) {
selectedPrinterId.value = printers.value[0]?.id || null
}
return true
} else {
error.value = response.error || 'Error al eliminar impresora'
return false
}
} catch (err: any) {
error.value = err.message
return false
} finally {
loading.value = false
}
}
async function selectPrinter(printerId: string | null) {
try {
const response = await $fetch<{
ok: boolean
error?: string
}>('/api/printers/select', {
method: 'POST',
body: { printerId }
})
if (response.ok) {
selectedPrinterId.value = printerId
return true
} else {
error.value = response.error || 'Error al seleccionar impresora'
return false
}
} catch (err: any) {
error.value = err.message
return false
}
}
return {
printers,
selectedPrinterId,
selectedPrinter,
defaultPrinter,
loading,
error,
fetchPrinters,
createPrinter,
updatePrinter,
deletePrinter,
selectPrinter
}
}