Data

ReportDesigner

Designer visuale a tre pannelli per report personalizzati — palette dei componenti, canvas righe/colonne con riordino drag-and-drop e editor delle proprietà con formula builder e validazione della sintassi per motore di calcolo.

Import

import { ReportDesigner } from '@pzeta/vue-components'
import type {
  ReportRiga,
  ReportColonna,
  ReportEspressione,
  ReportValidaFormula,
} from '@pzeta/vue-components'

Struttura

Il designer è organizzato in tre pannelli:

  • Palette (sinistra): aggiunta di righe/colonne e libreria di espressioni riutilizzabili;
  • Canvas (centro): righe riordinabili via drag-and-drop e colonne, con richiesta di anteprima;
  • Editor proprietà (destra): formula builder con validazione della sintassi per motore di calcolo.

Struttura dati

type ReportElementoTipo = 'riga' | 'colonna' | 'espressione'
type ReportMotore = string // es. 'sql' | 'javascript' | 'jsonata'

interface ReportRiga {
  id: string | number
  label: string
  formula?: string
  motore?: ReportMotore
  [key: string]: unknown  // proprietà aggiuntive di dominio
}

interface ReportColonna {
  id: string | number
  label: string
  campo?: string     // campo sorgente / chiave dati
  formato?: string   // es. 'valuta' | 'numero' | 'data'
  formula?: string   // per colonne calcolate
  motore?: ReportMotore
  [key: string]: unknown
}

interface ReportEspressione {
  id: string | number
  label: string
  formula: string
  motore: ReportMotore
  [key: string]: unknown
}

Esempio Base

Props

PropTipoDefaultDescrizione
righeReportRiga[][]Righe del report (asse verticale)
colonneReportColonna[][]Colonne del report (asse orizzontale)
espressioniReportEspressione[][]Libreria di espressioni riutilizzabili mostrate nella palette
motoriAbilitatiReportMotore[][]Motori di valutazione selezionabili nell'editor delle formule
validaFormulaReportValidaFormula | nullnullValidatore async della sintassi (null = formula valida)
titolostring | nullnullTitolo mostrato nell'intestazione del canvas
disabledbooleanfalseDisabilita ogni interazione (sola lettura)

Emits

EventoPayloadDescrizione
riordina-righe{ righe: ReportRiga[]; from: number; to: number }Righe riordinate via drag-and-drop
salva-rigaReportRigaSalvataggio di una riga dall'editor
salva-colonnaReportColonnaSalvataggio di una colonna dall'editor
salva-espressioneReportEspressioneSalvataggio di un'espressione dall'editor
elimina-elemento{ tipo: ReportElementoTipo; elemento: ReportElemento }Elemento eliminato dal canvas
preview{ righe: ReportRiga[]; colonne: ReportColonna[] }Richiesta di anteprima del report

Slot

SlotScopeDescrizione
preview{ righe: ReportRiga[]; colonne: ReportColonna[] }Render del risultato dell'anteprima
proprieta{ tipo: ReportElementoTipo; elemento: ReportElemento; motore?: ReportMotore }Editor di proprietà custom, tipicamente specifico per motore

Esempi

Validazione delle formule per motore

Il validatore riceve motore e formula e risolve null se la sintassi è valida, altrimenti il messaggio d'errore mostrato nell'editor.

<script setup lang="ts">
import type { ReportValidaFormula } from '@pzeta/vue-components'

const validaFormula: ReportValidaFormula = async (motore, formula) => {
  if (!formula.trim()) return 'La formula non può essere vuota'
  if (motore === 'sql' && !/^[A-Z_]+\(/.test(formula.trim())) {
    return 'Attesa una funzione di aggregazione (es. SUM(...))'
  }
  // Validazione remota opzionale:
  // const res = await api.validate(motore, formula)
  // return res.valid ? null : res.error
  return null
}
</script>

<template>
  <ReportDesigner
    :righe="righe"
    :colonne="colonne"
    :motori-abilitati="['sql', 'javascript', 'jsonata']"
    :valida-formula="validaFormula"
  />
</template>

Anteprima personalizzata

<template>
  <ReportDesigner :righe="righe" :colonne="colonne" @preview="onPreview">
    <template #preview="{ righe, colonne }">
      <table class="w-full text-sm">
        <thead>
          <tr>
            <th></th>
            <th v-for="c in colonne" :key="c.id">{{ c.label }}</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="r in righe" :key="r.id">
            <td class="font-medium">{{ r.label }}</td>
            <td v-for="c in colonne" :key="c.id"></td>
          </tr>
        </tbody>
      </table>
    </template>
  </ReportDesigner>
</template>

Sola lettura

<template>
  <ReportDesigner :righe="righe" :colonne="colonne" disabled />
</template>

Comportamento

  • Le righe si riordinano via drag-and-drop; ogni riordino emette riordina-righe con il nuovo ordine completo e gli indici from/to.
  • Il salvataggio di un elemento dall'editor emette l'evento salva-* corrispondente al tipo: la persistenza è responsabilità del consumer.
  • Con disabled il designer è in sola lettura e non emette eventi di modifica.

TypeScript

import type {
  ReportDesignerProps,
  ReportDesignerEmits,
  ReportDesignerSlots,
  ReportRiga,
  ReportColonna,
  ReportEspressione,
  ReportElemento,
  ReportElementoTipo,
  ReportMotore,
  ReportValidaFormula,
  ReportDesignerSelezione,
} from '@pzeta/vue-components'