Files
printerCentral/server/utils/templates.ts
josedario87 1d5838de6c
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 36s
feat: Endpoints para imprimir templates y operaciones con variables
- POST /api/print/template: Imprime un template guardado por ID con variables
- POST /api/print/raw: Imprime operaciones arbitrarias con soporte de variables inline
- Agregada función resolveVariables() en server/utils/templates.ts
2025-11-25 11:10:57 -06:00

196 lines
5.2 KiB
TypeScript

// Gestión de templates persistentes
import { readFile, writeFile, mkdir } from 'fs/promises'
import { existsSync } from 'fs'
import { join } from 'path'
export interface Operation {
op: string
[key: string]: any
}
export interface TemplateVariable {
name: string
label?: string
defaultValue?: string
}
export interface PrintTemplate {
id: string
name: string
description?: string
operations: Operation[]
variables: TemplateVariable[]
createdAt: string
updatedAt: string
}
// Regex para detectar {{nombre}}, {{nombre:label}}, {{nombre:label:default}}
const VARIABLE_REGEX = /\{\{(\w+)(?::([^:}]+))?(?::([^}]+))?\}\}/g
// Extraer variables de las operaciones
export function extractVariables(operations: Operation[]): TemplateVariable[] {
const variablesMap = new Map<string, TemplateVariable>()
for (const op of operations) {
// Buscar en campos que pueden contener variables
const searchFields = ['value', 'data']
for (const field of searchFields) {
if (typeof op[field] === 'string') {
const matches = op[field].matchAll(VARIABLE_REGEX)
for (const match of matches) {
const [, name, label, defaultValue] = match
// Solo guardar la primera definición de cada variable
if (!variablesMap.has(name)) {
variablesMap.set(name, {
name,
label: label || undefined,
defaultValue: defaultValue || undefined
})
}
}
}
}
}
return Array.from(variablesMap.values())
}
// Resolver variables en operaciones reemplazando {{nombre}} con valores
export function resolveVariables(
operations: Operation[],
values: Record<string, string> = {}
): Operation[] {
return JSON.parse(JSON.stringify(operations)).map((op: Operation) => {
for (const [key, val] of Object.entries(op)) {
if (typeof val === 'string') {
op[key] = val.replace(VARIABLE_REGEX, (_, name) => values[name] ?? '')
}
}
return op
})
}
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<void> {
if (!existsSync(DATA_DIR)) {
await mkdir(DATA_DIR, { recursive: true })
}
}
// Leer store de templates
export async function readTemplatesStore(): Promise<TemplatesStore> {
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<void> {
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<PrintTemplate[]> {
const store = await readTemplatesStore()
return store.templates
}
export async function getTemplateById(id: string): Promise<PrintTemplate | null> {
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<PrintTemplate> {
const store = await readTemplatesStore()
const now = new Date().toISOString()
const template: PrintTemplate = {
id: generateId(),
name: data.name,
description: data.description || '',
operations: data.operations,
variables: extractVariables(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<PrintTemplate | null> {
const store = await readTemplatesStore()
const index = store.templates.findIndex(t => t.id === id)
if (index === -1) return null
// Si se actualizan las operaciones, recalcular las variables
const variables = data.operations
? extractVariables(data.operations)
: store.templates[index].variables
store.templates[index] = {
...store.templates[index],
...data,
variables,
updatedAt: new Date().toISOString()
}
await writeTemplatesStore(store)
return store.templates[index]
}
export async function deleteTemplate(id: string): Promise<boolean> {
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<PrintTemplate | null> {
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))
})
}