+
+
+
+
+
No hay templates guardados
diff --git a/app/composables/useTemplates.ts b/app/composables/useTemplates.ts
index c1866bf..70c9f7c 100644
--- a/app/composables/useTemplates.ts
+++ b/app/composables/useTemplates.ts
@@ -5,92 +5,116 @@ export interface PrintTemplate {
name: string
description?: string
operations: Operation[]
- createdAt: number
- updatedAt: number
-}
-
-const STORAGE_KEY = 'printercentral-templates'
-
-// Función para generar UUID compatible con todos los navegadores
-function generateId(): string {
- if (typeof crypto !== 'undefined' && crypto.randomUUID) {
- return crypto.randomUUID()
- }
- // Fallback para navegadores sin crypto.randomUUID
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
- const r = Math.random() * 16 | 0
- const v = c === 'x' ? r : (r & 0x3 | 0x8)
- return v.toString(16)
- })
+ createdAt: string
+ updatedAt: string
}
export function useTemplates() {
const templates = useState('templates', () => [])
- const initialized = useState('templatesInitialized', () => false)
+ const loading = useState('templatesLoading', () => false)
+ const error = useState('templatesError', () => null)
- // Cargar de localStorage al iniciar (solo cliente)
- if (import.meta.client && !initialized.value) {
- const stored = localStorage.getItem(STORAGE_KEY)
- if (stored) {
- try {
- templates.value = JSON.parse(stored)
- } catch (e) {
- console.error('Error parsing templates:', e)
- }
- }
- initialized.value = true
- }
-
- // Guardar en localStorage cuando cambie
- watch(templates, (val) => {
- if (import.meta.client) {
- localStorage.setItem(STORAGE_KEY, JSON.stringify(val))
- }
- }, { deep: true })
-
- function saveTemplate(name: string, description: string, operations: Operation[]): PrintTemplate {
- const template: PrintTemplate = {
- id: generateId(),
- name,
- description,
- operations: JSON.parse(JSON.stringify(operations)),
- createdAt: Date.now(),
- updatedAt: Date.now()
- }
- templates.value = [...templates.value, template]
- return template
- }
-
- function updateTemplate(id: string, updates: Partial>) {
- const idx = templates.value.findIndex(t => t.id === id)
- if (idx !== -1) {
- templates.value = templates.value.map((t, i) =>
- i === idx ? { ...t, ...updates, updatedAt: Date.now() } : t
- )
+ // Cargar templates del servidor
+ async function fetchTemplates(): Promise {
+ loading.value = true
+ error.value = null
+ try {
+ const data = await $fetch('/api/templates')
+ templates.value = data
+ } catch (e) {
+ console.error('Error fetching templates:', e)
+ error.value = 'Error al cargar templates'
+ } finally {
+ loading.value = false
}
}
- function deleteTemplate(id: string) {
- templates.value = templates.value.filter(t => t.id !== id)
+ // Guardar nuevo template
+ async function saveTemplate(
+ name: string,
+ description: string,
+ operations: Operation[]
+ ): Promise {
+ error.value = null
+ try {
+ const template = await $fetch('/api/templates', {
+ method: 'POST',
+ body: {
+ name,
+ description,
+ operations
+ }
+ })
+ templates.value = [...templates.value, template]
+ return template
+ } catch (e) {
+ console.error('Error saving template:', e)
+ error.value = 'Error al guardar template'
+ return null
+ }
}
+ // Actualizar template existente
+ async function updateTemplate(
+ id: string,
+ updates: Partial<{ name: string; description: string; operations: Operation[] }>
+ ): Promise {
+ error.value = null
+ try {
+ const template = await $fetch(`/api/templates/${id}`, {
+ method: 'PUT',
+ body: updates
+ })
+ templates.value = templates.value.map(t => t.id === id ? template : t)
+ return template
+ } catch (e) {
+ console.error('Error updating template:', e)
+ error.value = 'Error al actualizar template'
+ return null
+ }
+ }
+
+ // Eliminar template
+ async function deleteTemplate(id: string): Promise {
+ error.value = null
+ try {
+ await $fetch(`/api/templates/${id}`, { method: 'DELETE' })
+ templates.value = templates.value.filter(t => t.id !== id)
+ return true
+ } catch (e) {
+ console.error('Error deleting template:', e)
+ error.value = 'Error al eliminar template'
+ return false
+ }
+ }
+
+ // Cargar operaciones de un template
function loadTemplate(id: string): Operation[] | null {
const template = templates.value.find(t => t.id === id)
return template ? JSON.parse(JSON.stringify(template.operations)) : null
}
- function duplicateTemplate(id: string): PrintTemplate | null {
- const template = templates.value.find(t => t.id === id)
- if (!template) return null
- return saveTemplate(
- `${template.name} (copia)`,
- template.description || '',
- template.operations
- )
+ // Duplicar template
+ async function duplicateTemplate(id: string): Promise {
+ error.value = null
+ try {
+ const template = await $fetch(`/api/templates/${id}/duplicate`, {
+ method: 'POST'
+ })
+ templates.value = [...templates.value, template]
+ return template
+ } catch (e) {
+ console.error('Error duplicating template:', e)
+ error.value = 'Error al duplicar template'
+ return null
+ }
}
return {
templates: readonly(templates),
+ loading: readonly(loading),
+ error: readonly(error),
+ fetchTemplates,
saveTemplate,
updateTemplate,
deleteTemplate,
diff --git a/app/pages/index.vue b/app/pages/index.vue
index ac48086..f3b6235 100644
--- a/app/pages/index.vue
+++ b/app/pages/index.vue
@@ -63,7 +63,6 @@ onMounted(() => {
-
@@ -85,14 +84,14 @@ onMounted(() => {
-
-
+
+
Gestión de Impresoras
-
-
+
+
diff --git a/server/api/templates/[id].delete.ts b/server/api/templates/[id].delete.ts
new file mode 100644
index 0000000..4eff177
--- /dev/null
+++ b/server/api/templates/[id].delete.ts
@@ -0,0 +1,23 @@
+import { deleteTemplate } from '../../utils/templates'
+
+export default defineEventHandler(async (event) => {
+ const id = getRouterParam(event, 'id')
+
+ if (!id) {
+ throw createError({
+ statusCode: 400,
+ message: 'ID requerido'
+ })
+ }
+
+ const success = await deleteTemplate(id)
+
+ if (!success) {
+ throw createError({
+ statusCode: 404,
+ message: 'Template no encontrado'
+ })
+ }
+
+ return { success: true }
+})
diff --git a/server/api/templates/[id].get.ts b/server/api/templates/[id].get.ts
new file mode 100644
index 0000000..06f5e05
--- /dev/null
+++ b/server/api/templates/[id].get.ts
@@ -0,0 +1,23 @@
+import { getTemplateById } from '../../utils/templates'
+
+export default defineEventHandler(async (event) => {
+ const id = getRouterParam(event, 'id')
+
+ if (!id) {
+ throw createError({
+ statusCode: 400,
+ message: 'ID requerido'
+ })
+ }
+
+ const template = await getTemplateById(id)
+
+ if (!template) {
+ throw createError({
+ statusCode: 404,
+ message: 'Template no encontrado'
+ })
+ }
+
+ return template
+})
diff --git a/server/api/templates/[id].put.ts b/server/api/templates/[id].put.ts
new file mode 100644
index 0000000..4883d2e
--- /dev/null
+++ b/server/api/templates/[id].put.ts
@@ -0,0 +1,28 @@
+import { updateTemplate } from '../../utils/templates'
+
+export default defineEventHandler(async (event) => {
+ const id = getRouterParam(event, 'id')
+ const body = await readBody(event)
+
+ if (!id) {
+ throw createError({
+ statusCode: 400,
+ message: 'ID requerido'
+ })
+ }
+
+ const template = await updateTemplate(id, {
+ name: body.name,
+ description: body.description,
+ operations: body.operations
+ })
+
+ if (!template) {
+ throw createError({
+ statusCode: 404,
+ message: 'Template no encontrado'
+ })
+ }
+
+ return template
+})
diff --git a/server/api/templates/[id]/duplicate.post.ts b/server/api/templates/[id]/duplicate.post.ts
new file mode 100644
index 0000000..4c3bd97
--- /dev/null
+++ b/server/api/templates/[id]/duplicate.post.ts
@@ -0,0 +1,23 @@
+import { duplicateTemplate } from '../../../utils/templates'
+
+export default defineEventHandler(async (event) => {
+ const id = getRouterParam(event, 'id')
+
+ if (!id) {
+ throw createError({
+ statusCode: 400,
+ message: 'ID requerido'
+ })
+ }
+
+ const template = await duplicateTemplate(id)
+
+ if (!template) {
+ throw createError({
+ statusCode: 404,
+ message: 'Template no encontrado'
+ })
+ }
+
+ return template
+})
diff --git a/server/api/templates/index.get.ts b/server/api/templates/index.get.ts
new file mode 100644
index 0000000..d4f36d9
--- /dev/null
+++ b/server/api/templates/index.get.ts
@@ -0,0 +1,6 @@
+import { getAllTemplates } from '../../utils/templates'
+
+export default defineEventHandler(async () => {
+ const templates = await getAllTemplates()
+ return templates
+})
diff --git a/server/api/templates/index.post.ts b/server/api/templates/index.post.ts
new file mode 100644
index 0000000..3ae9a03
--- /dev/null
+++ b/server/api/templates/index.post.ts
@@ -0,0 +1,27 @@
+import { createTemplate } from '../../utils/templates'
+
+export default defineEventHandler(async (event) => {
+ const body = await readBody(event)
+
+ if (!body.name) {
+ throw createError({
+ statusCode: 400,
+ message: 'El nombre es requerido'
+ })
+ }
+
+ if (!body.operations || !Array.isArray(body.operations)) {
+ throw createError({
+ statusCode: 400,
+ message: 'Las operaciones son requeridas'
+ })
+ }
+
+ const template = await createTemplate({
+ name: body.name,
+ description: body.description,
+ operations: body.operations
+ })
+
+ return template
+})
diff --git a/server/utils/templates.ts b/server/utils/templates.ts
new file mode 100644
index 0000000..bb4f700
--- /dev/null
+++ b/server/utils/templates.ts
@@ -0,0 +1,136 @@
+// Gestión de templates persistentes
+import { readFile, writeFile, mkdir } from 'fs/promises'
+import { existsSync } from 'fs'
+import { join } from 'path'
+
+export interface Operation {
+ id: string
+ type: 'text' | 'feed' | 'cut' | 'pulse' | 'image' | 'barcode' | 'qrcode'
+ params: Record
+}
+
+export interface PrintTemplate {
+ id: string
+ name: string
+ description?: string
+ operations: Operation[]
+ createdAt: string
+ updatedAt: string
+}
+
+export interface TemplatesStore {
+ templates: PrintTemplate[]
+}
+
+// Directorio de datos persistentes
+const DATA_DIR = join(process.cwd(), 'data')
+const TEMPLATES_FILE = join(DATA_DIR, 'templates.json')
+
+// Asegurar que el directorio existe
+async function ensureDataDir(): Promise {
+ if (!existsSync(DATA_DIR)) {
+ await mkdir(DATA_DIR, { recursive: true })
+ }
+}
+
+// Leer store de templates
+export async function readTemplatesStore(): Promise {
+ await ensureDataDir()
+
+ try {
+ const data = await readFile(TEMPLATES_FILE, 'utf-8')
+ return JSON.parse(data)
+ } catch {
+ // Si no existe el archivo, retornar store vacío
+ return {
+ templates: []
+ }
+ }
+}
+
+// Guardar store de templates
+export async function writeTemplatesStore(store: TemplatesStore): Promise {
+ await ensureDataDir()
+ await writeFile(TEMPLATES_FILE, JSON.stringify(store, null, 2), 'utf-8')
+}
+
+// Generar ID único
+function generateId(): string {
+ return `template_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`
+}
+
+// CRUD Operations
+
+export async function getAllTemplates(): Promise {
+ const store = await readTemplatesStore()
+ return store.templates
+}
+
+export async function getTemplateById(id: string): Promise {
+ const store = await readTemplatesStore()
+ return store.templates.find(t => t.id === id) || null
+}
+
+export async function createTemplate(data: {
+ name: string
+ description?: string
+ operations: Operation[]
+}): Promise {
+ const store = await readTemplatesStore()
+
+ const now = new Date().toISOString()
+ const template: PrintTemplate = {
+ id: generateId(),
+ name: data.name,
+ description: data.description || '',
+ operations: data.operations,
+ createdAt: now,
+ updatedAt: now
+ }
+
+ store.templates.push(template)
+ await writeTemplatesStore(store)
+ return template
+}
+
+export async function updateTemplate(id: string, data: Partial<{
+ name: string
+ description: string
+ operations: Operation[]
+}>): Promise {
+ const store = await readTemplatesStore()
+ const index = store.templates.findIndex(t => t.id === id)
+
+ if (index === -1) return null
+
+ store.templates[index] = {
+ ...store.templates[index],
+ ...data,
+ updatedAt: new Date().toISOString()
+ }
+
+ await writeTemplatesStore(store)
+ return store.templates[index]
+}
+
+export async function deleteTemplate(id: string): Promise {
+ const store = await readTemplatesStore()
+ const index = store.templates.findIndex(t => t.id === id)
+
+ if (index === -1) return false
+
+ store.templates.splice(index, 1)
+ await writeTemplatesStore(store)
+ return true
+}
+
+export async function duplicateTemplate(id: string): Promise {
+ const template = await getTemplateById(id)
+ if (!template) return null
+
+ return createTemplate({
+ name: `${template.name} (copia)`,
+ description: template.description,
+ operations: JSON.parse(JSON.stringify(template.operations))
+ })
+}