Keine andere Programmiersprache. Teil 2: Repräsentationslogik



Der zweite Teil der lsFusion-Sprach- und Plattform-Trilogie. Der erste Teil ist hier zu finden.

Es wird sich auf die Logik von Darstellungen konzentrieren, nämlich auf alles, was mit dem Kombinieren und Anzeigen von Daten für den Benutzer oder andere Informationssysteme zusammenhängt.

Es ist klar, dass viele nicht so sehr daran interessiert sind, die Präsentation des Kämpfers zu betrachten, und sie würden gerne einen echten Kampf sehen, wenn möglich mit Blut (und das wird auch so sein, da die Diskussion der vorherigen Artikel dazu beigetragen hat, die ungeschützten Orte potenzieller Konkurrenten besser zu verstehen und wo man sie schlagen kann). . Es sind jedoch zwei Dinge zu beachten:

a) das ist Habr. Das heißt, eine technische Ressource, sie mögen hier keine schönen Bilder und Werbeslogans - um etwas zu sagen, benötigen Sie Details darüber, wie Sie dies erreichen werden.
b) Es ist ein Markt für die Entwicklung von Informationssystemen und dem Markt für Produkte zur Gewichtsreduktion sehr ähnlich. Hier sagen alle, dass wir schnell und einfach haben. Aber wenn es um Details geht, in denen, wie Sie wissen, der Teufel liegt, werden entweder die einfachsten CRUDs als Beispiele verwendet oder sie greifen auf verschiedene Tricks zurück: Sie zeigen einige Codeausschnitte und verbergen den Hauptteil mit den Worten "es spielt keine Rolle" "," Fertig in ein paar Minuten "und alles so.

Aus diesem Grund hatten wir zwei Möglichkeiten: entweder mit den Vorteilen und Risiken von Vorwürfen für Marketing-Bullshit beginnen oder mit einer technischen Beschreibung und den Fragen „Warum brauchen wir eine andere Sprache?“. Theoretisch könnte dies alles natürlich in einem Artikel erledigt werden, aber ein solcher Artikel wäre nicht nur schwer zu lesen, sondern auch nur durchzublättern. Dementsprechend haben wir uns für die zweite Option entschieden. Wenn es jedoch immer noch wichtig ist, dass jemand die Gründe für das Erscheinungsbild und die Vorteile der Sprache im Moment (und nicht in zukünftigen Artikeln) kennt, sind Sie auf der Website willkommen. Es besteht nur aus drei Seiten: Was, Wie und Warum nicht und gibt meiner Meinung nach genügend Informationen, um all diese Fragen zu beantworten. Außerdem können Sie die Plattform dort online testen , um sicherzustellen, dass sich dort kein „Klavier im Gebüsch“ befindet, und der Code aus den Beispielen in diesem Artikel ist wirklich der gesamte Code, der zum Ausführen der Anwendung erforderlich ist.

Aber genug lyrische Abweichungen, wir kehren zur Darstellung der Kämpferbeschreibung der Logik der Darstellungen zurück.

Wie die Domänenlogik (erster Artikel) bilden alle Konzepte der Präsentationslogik in lsFusion einen Stapel:



und in der Reihenfolge dieses Stapels werde ich darüber sprechen.


Formulare


Ein Formular ist das wichtigste (und praktisch praktisch einzige) Konzept in der Präsentationslogik, das für alles verantwortlich ist - sowohl für die Benutzerinteraktion als auch für das Drucken, Exportieren und Importieren von Daten.

Das Formular kann logisch in zwei Teile unterteilt werden:

  • Die Struktur des Formulars bestimmt, welche Daten das Formular anzeigt.
  • Die Darstellung des Formulars bestimmt, wie diese Daten angezeigt werden.

Formstruktur


Wir beginnen natürlich mit der Struktur der Form.

Die Objekte


Beim Erstellen eines Formulars müssen Sie zunächst festlegen, welche Objekte angezeigt werden sollen. Es ist anzumerken, dass die Terminologie zwischen den Objekten des Formulars und den Objekten, die in diesen Formularobjekten angezeigt werden, leicht verwechselt werden kann. Wenn dies in Zukunft aus dem Kontext nicht ersichtlich ist, werden wir daher in Zukunft die Begriffe "Formularobjekte" (für den ersten Fall) und "Objekte in der Datenbank" (für den zweiten Fall) verwenden.

Für jedes Formularobjekt müssen Sie seine Klasse festlegen. Diese Klasse kann entweder primitiv (integriert) oder objektorientiert (benutzerdefiniert) sein.
FORM currentBalances ' '
OBJECTS s = Stock, i = Item // ,
;
Entsprechend der Reihenfolge des Hinzufügens von Objekten zum Formular wird eine geordnete Liste von Objekten erstellt. Dementsprechend wird das letzte Objekt für eine bestimmte Gruppe von Objekten als Objekt aus dieser Gruppe mit der maximalen Seriennummer in dieser Liste (dh der neuesten) bezeichnet.

Jedes Objekt im Formular hat zu einem bestimmten Zeitpunkt einen aktuellen Wert. Die Änderung erfolgt je nach Präsentation entweder aufgrund der entsprechenden Aktionen des Benutzers in der interaktiven Präsentation oder "virtuell" beim Lesen von Daten in einer statischen Darstellung.

Eigenschaften und Aktionen


Nachdem Sie die Objekte im Formular definiert haben, können Sie Eigenschaften und Aktionen hinzufügen und diese durch die oben beschriebenen Objekte als Eingabe für die Argumente ersetzen.

Beachten Sie, dass das Hinzufügen von Aktionen nur für die interaktive Präsentation relevant ist und in Berichten und Exporten ignoriert wird. Da das Verhalten von Eigenschaften und Aktionen unter dem Gesichtspunkt ihrer Anzeige auf dem Formular genau das gleiche ist, werden wir in Zukunft nur den Begriff Eigenschaft verwenden (für Aktionen ist das Verhalten genau das gleiche).

Objekt anzeigen


Jede Eigenschaft wird in genau einem Objekt im Formular angezeigt (wir nennen es das Anzeigeobjekt dieser Eigenschaft). Standardmäßig ist das Anzeigeobjekt ein Objekt, letzteres für die Gruppe von Objekten, die an die Eingabe dieser Eigenschaft übergeben werden. Wenn wir zum Beispiel eine Form von aktuellen Salden mit zwei Objekten haben - einem Lager und Waren sowie drei Eigenschaften - Namen des Lagers und der Waren und der Warenbilanz im Lager:
FORM currentBalances ' '
OBJECTS s = Stock, i = Item // ,
PROPERTIES name(s), name(i), currentBalance(s, i)
;
Dann lautet das Anzeigeobjekt für den Namen des Lagers s (Lager) und für den Namen der Waren und den Saldo i (Waren).

Bei Bedarf kann der Entwickler das Anzeigeobjekt jedoch explizit angeben (dh in einer interaktiven Ansicht die Eigenschaft mit dem Rest in der Lagertabelle anzeigen, nicht Waren).

Filter und Sortierung


Für jedes Formular kann der Entwickler Filter und Aufträge festlegen, die die Liste der Objekte, die zum Anzeigen / Auswählen im Formular verfügbar sind, sowie die Reihenfolge, in der sie angezeigt werden, einschränken.

Um einen Filter festzulegen, müssen Sie eine Eigenschaft angeben, die als Filterkriterium verwendet wird. Der Filter wird auf die Tabelle dieses Objekts angewendet. Dies ist der letzte für die Gruppe von Objekten, die an die Eingabe dieser Eigenschaft übergeben werden (dh ähnlich wie bei der Definition des Eigenschaftsanzeigeobjekts). In diesem Fall werden nur die Objektgruppen (Serien) angezeigt, für die die Eigenschaftswerte nicht NULL sind. Wenn wir beispielsweise den Filter currentBalance (s, i) OR isActive (i) zum obigen Formular hinzufügen:
FORM currentBalances ' '
OBJECTS s = Stock, i = Item // ,
PROPERTIES name(s), name(i), currentBalance(s, i)
FILTERS currentBalance(s, i) OR isActive(i)
;
Screenshot erstellen


Bei der Anzeige von Produkten werden nur Produkte angezeigt, die sich auf der Waage befinden oder als aktiv markiert sind.

Sortierungen werden als Liste von Eigenschaften in dem Formular definiert, in der Reihenfolgeobjekte angezeigt werden sollen. Ansonsten ist alles ähnlich wie bei Filtern.

Gruppen von Objekten


Die Plattform bietet auch die Möglichkeit, Objekte zu einer Gruppe von Objekten zu kombinieren. In diesem Fall wird das „kartesische Produkt“ dieser Objekte in den Tabellen / Listen angezeigt (dh für zwei Objekte - alle Paare, drei Objekte - Dreifachobjekte usw.).
FORM currentBalances ' '
OBJECTS (s = Stock, i = Item) //
PROPERTIES name(s), name(i), currentBalance(s, i)
FILTERS currentBalance(s, i) OR isActive(i)
;
Screenshot erstellen


Dementsprechend können Sie fast überall, sowohl vorher als auch nachher, anstelle einzelner Objekte des Formulars Gruppen von Objekten verwenden.

Tatsächlich wurde dies in der Dokumentation getan: Der allgemeinere Begriff „Gruppe von Objekten“ wird überall verwendet, aber um die Dinge in diesem Artikel nicht zu komplizieren (und Gruppen von Objekten, die aus mehreren Objekten bestehen, werden viel seltener verwendet), wurde beschlossen, Gruppen von Objekten zu vergessen und zu zählen. dass eine Gruppe von Objekten immer aus genau einem Objekt besteht und dementsprechend überall den Begriff „Objekt“ anstelle der komplexeren „Gruppe von Objekten“ und „Menge von Objekten“ verwendet.

Eigenschaftsgruppen


Eigenschaften des Formulars können wie Objekte auch zu Gruppen zusammengefasst werden, die wiederum in den interaktiven (Standarddesign) und hierarchischen Darstellungen des Formulars (etwas später) verwendet werden. Standardmäßig ist die Bindung einer Eigenschaft an eine Gruppe global (dh sie wird für eine Eigenschaft für alle Formulare gleichzeitig festgelegt). Bei Bedarf kann diese Bindung jedoch für einzelne Formulare neu definiert werden.

Spaltenobjekte


Standardmäßig wird eine Eigenschaft in ihrem Anzeigeobjekt genau einmal angezeigt. In diesem Fall werden als Werte anderer Objekte als des Anzeigeobjekts dieser Eigenschaft (wir nennen sie obere) ihre aktuellen Werte verwendet. Die Plattform kann jedoch auch eine Eigenschaft mehrmals anzeigen, sodass die Werte einiger Top-Objekte nicht von ihren aktuellen Werten verwendet werden, sondern von allen Objekten in der Datenbank, die für Filter geeignet sind. Bei dieser Zuordnung von Eigenschaften wird eine Art „Matrix“ gebildet - (Anzeigeobjekt) x (obere Objekte). Um eine solche Matrix zu erstellen, muss beim Hinzufügen einer Eigenschaft zum Formular angegeben werden, welche oberen Objekte zum Erstellen von Spalten verwendet werden sollen (wir werden diese Objekte Objekte in Spalten nennen).
FORM currentBalances ' '
// ,
//
OBJECTS s = Stock, i = Item
//
PROPERTIES name(i), currentBalance(s, i) COLUMNS (s) HEADER name(s)
FILTERS isActive(i), isActive(s)
;
Screenshot erstellen


Lassen Sie uns nun mit dem, was das Formular mehr oder weniger herausgefunden hat, fortfahren, wie es dies tun kann.

Formularübermittlungen


Es gibt drei Formulareingaben:



Screenshots anzeigen
Interaktiv:



Gedruckt:



Strukturiert:



  • Interaktiv. Eine Ansicht, mit der der Benutzer interagieren kann, besteht darin, Daten und aktuelle Objekte durch Auslösen verschiedener Ereignisse zu ändern. Tatsächlich wird diese Darstellung normalerweise als Formular bezeichnet.
  • Gedruckt. Es wird normalerweise als Bericht bezeichnet, bei dem alle Formulardaten hochgeladen und in grafischer Form dargestellt werden. Einschließlich der Möglichkeit, sie zu drucken (von wo es seinen Namen hat).
  • Strukturiert - Darstellung des Formulars in verschiedenen strukturierten Formaten (JSON, XML, DBF usw.). Wird normalerweise für die weitere Integration mit anderen Systemen verwendet.

Interaktive und gedruckte Darstellungen sind grafisch, dh sie zeigen die empfangenen Daten im zweidimensionalen Raum an: Papier oder den Bildschirm des Geräts. Dementsprechend hat jede dieser Darstellungen ein Design, das abhängig von der jeweiligen Darstellung unter Verwendung geeigneter Mechanismen (etwas später) eingestellt werden kann.

Die gedruckte und strukturierte Präsentation ist statisch, dh sie liest alle Daten zum Zeitpunkt des Öffnens des Formulars (im Gegensatz zur interaktiven Präsentation, bei der die Daten nach Bedarf gelesen werden).

Die Beschreibung der Aufführungen beginnt vielleicht mit der schwierigsten - der interaktiven Präsentation.

Interaktive Präsentation


In einer interaktiven Ansicht werden Formularobjekte in Tabellenform angezeigt. Die Zeilen in dieser Tabelle entsprechen den Objekten in der Datenbank, die die angegebenen Filter erfüllen. Die Spalten entsprechen wiederum den Eigenschaften.

Bei Bedarf kann die Eigenschaft jedoch nicht als Tabellenspalte, dh für alle Zeilen, sondern als separates Feld im Formular angezeigt werden, dh nur für den aktuellen Wert des Formularobjekts. Zum Beispiel:
currentBalance ' ' (Stock s) = GROUP SUM currentBalance(s, Item i);
FORM currentBalances ' '
OBJECTS s = Stock, i = Item
// currentBalance(s) ,
PROPERTIES name(s), currentBalance(s) PANEL ,
name(i), currentBalance(s, i)
FILTERS currentBalance(s, i)
;
Screenshot erstellen


Das Ändern des aktuellen Werts eines Formularobjekts erfolgt entweder durch Ändern der aktuellen Zeile der Tabelle durch einen Benutzer oder durch Ausführen einer Aktion, die mit einem speziellen Suchoperator (SEEK) erstellt wurde.

Beachten Sie, dass die Art und Weise, wie eine Eigenschaft in einem Bedienfeld oder einer Tabelle angezeigt wird, in der Regel nicht für jede Eigenschaft einzeln, sondern als Ganzes für ein Formularobjekt festgelegt wird. Wenn das Formularobjekt als PANEL markiert ist, werden dementsprechend alle seine Eigenschaften im Bedienfeld angezeigt (dh für den aktuellen Wert), andernfalls (standardmäßig) werden alle seine Eigenschaften in der Tabelle angezeigt. Eigenschaften ohne Parameter und Standardaktionen werden im Bedienfeld angezeigt.

Alle Tabellen in der interaktiven Ansicht sind standardmäßig dynamisch, dh es wird nur eine begrenzte Anzahl von Objekten in der Datenbank gelesen, und der Rest wird gelesen, wenn sich das aktuelle Objekt in der Tabelle ändert. Die Anzahl der angezeigten Objekte kann in diesem Fall entweder automatisch anhand der Höhe des sichtbaren Teils der Tabelle ermittelt oder vom Entwickler beim Erstellen des Formulars explizit festgelegt werden.

Außerdem ist das Formular in der interaktiven Präsentation vollständig reaktiv, dh es aktualisiert automatisch alle Daten im Formular, wenn sich Daten ändern, die sie betreffen (z. B. Reagieren, nur im allgemeinen Fall). Darüber hinaus erfolgt dies nicht durch vollständige Neuberechnung (wie in derselben Reaktion), sondern schrittweise auf dem SQL Server.

Im Allgemeinen ist es lustig, wenn Sie im Vergleich zu anderen Technologien versuchen, die drei wichtigsten Anforderungen in die Aufgabe einzubeziehen. Menschen machen oft runde Augen, als ob sie gebeten würden, eine Person in den Weltraum zu bringen. Obwohl die Nichterfüllung der zweiten Anforderung durch einen normalen Benutzer als Fehler eingestuft wird und die erste und dritte Anforderung darin besteht, dass das entwickelte Formular normal funktioniert, wenn mindestens wenige Daten in der Datenbank angezeigt werden (z. B. mehrere Zehntausend Datensätze).

Die interaktive Präsentation wird sowohl im Webclient-Modus (d. H. Webanwendungen in einem Browser) als auch im Desktop-Client-Modus (Java-Anwendungen) unterstützt. Der Desktop-Client reagiert wie jeder native Client etwas besser auf die Benutzeroberfläche. Am wichtigsten ist jedoch, dass Sie mit Geräten arbeiten und andere Vorgänge ausführen können, die im Browser nicht verfügbar sind (hauptsächlich aufgrund von Sicherheitsproblemen).

Objektbäume


Neben Tabellen können Sie auf der Plattform auch die Anzeige von Objekten in Form von Bäumen organisieren, sowohl flach (ineinander verschachtelte "Tabellen) als auch rekursiv (z. B." verschachtelte "Objekte in der Datenbank).

Flache Bäume sind in der Tat eine Verallgemeinerung von Tabellen, wenn mehrere Tabellen gleichzeitig zu einer Tabelle "kombiniert" werden:
FORM currentBalances ' '
TREE tree s = Stock, i = Item
//
//
PROPERTIES name(s), currentBalance(s),
name(i), currentBalance(s, i)
;
Screenshot erstellen


Dies ist ein relativ komplexer Mechanismus, der in der Praxis nur selten angewendet wird. Wir werden daher nicht näher darauf eingehen.

Im Gegensatz dazu werden rekursive Bäume jedoch häufig verwendet (z. B. um Implementierer zu implementieren). Um ein Formularobjekt in Form eines solchen Baums anzuzeigen, muss ein zusätzlicher Filter dafür festgelegt werden - eine Eigenschaft, deren Wert für die unteren Objekte gleich dem oberen Objekt sein sollte. Anfangs wird das oberste Objekt als NULL betrachtet.
parent = DATA ItemGroup (ItemGroup) IN base;
group = DATA ItemGroup (Item) IN base;
//
level '' (ItemGroup child, ItemGroup parent) = RECURSION 1 AND child IS ItemGroup AND parent = child STEP 1 IF parent = parent($parent);
currentBalance ' ' (ItemGroup ig, Stock s) = GROUP SUM currentBalance(s, Item i) IF level(ig, group(i));

FORM currentBalances ' '
OBJECTS s=Stock PANEL //
PROPERTIES (s) name
TREE tree ig = ItemGroup PARENT parent, i = Item // /
PROPERTIES name(ig), currentBalance(ig, s)
PROPERTIES name(i), currentBalance(s, i)
FILTERS group(i) = ig
;
Screenshot erstellen


Benutzerformularverwaltung


Um eine bessere Ergonomie des Systems zu gewährleisten (einschließlich der Erstellung von Formularen nicht für alle), kann ein Teil der Vorgänge zum Einrichten der interaktiven Präsentation des Formulars von den Benutzern selbst ausgeführt werden. Zum Beispiel sind solche Operationen:

  • Einrichtung von Tabellen (sichtbare Spalten, Reihenfolge, Schriftarten usw.),
  • Erstellen von benutzerdefinierten Filtern und Sortierungen,
  • Gruppieren von Daten nach Spaltenwerten,
  • Drucken Sie eine Tabelle und laden Sie sie nach Excel hoch.

Der Entwickler kann auch sogenannte Filtergruppen erstellen, die der Benutzer unabhängig ein- und ausschalten kann. Zum Beispiel:
EXTEND FORM currentBalances //
FILTERGROUP stockActive // , , /
FILTER '' active(st) 'F11' // , F11
FILTERGROUP bal
FILTER ' ' currentBalance(st, sk) > 0 'F10'
FILTER ' ' currentBalance(st, sk) < 0 'F9'
FILTER ' ' currentBalance(st, sk) 'F8' DEFAULT
FILTER ' ' NOT currentBalance(st, sk) 'F7'
;
Dies sind nicht alle Möglichkeiten, das System durch den Benutzer anzupassen, aber wir werden auf die anderen Möglichkeiten im dritten Artikel zurückkommen, da die meisten von ihnen noch keinen direkten Bezug zur Präsentationslogik haben.

Beachten Sie, dass sich die oben beschriebene Funktionalität eher auf die Funktionalität von ERP-Plattformen bezieht, die bereits vollständig mit dem Titel des Artikels nicht übereinstimmt. Andererseits behauptet die Sprache / Plattform, wie im ersten Artikel erwähnt, in Zukunft ein Ersatz zu sein, einschließlich dieser Klasse von Plattformen, so dass es falsch wäre, diese Funktionen überhaupt nicht zu erwähnen.

Objektoperatoren


Eines der häufigsten Szenarien beim Arbeiten mit einem Formular ist das Hinzufügen / Löschen eines Objekts sowie das Bearbeiten in einem neuen Formular. Um solche Szenarien zu implementieren, verfügt die Plattform über einen vordefinierten Satz von Operatoren, mit denen Sie die erforderlichen Aktionen in einem Wort direkt im Formularerstellungsoperator erstellen können:

  • NEU - Objekt erstellen
  • BEARBEITEN - Bearbeiten eines Objekts
  • NEWEDIT - Erstellen und Bearbeiten eines Objekts
  • LÖSCHEN - Löscht ein Objekt

Da es sehr häufig erforderlich ist, diese Aktionen in einer neuen Sitzung auszuführen (wenn Sie die Aktionen zum Erstellen von Objekten von den Aktionen in dem Formular trennen müssen, aus dem diese Objekte erstellt werden), unterstützt die Plattform den entsprechenden syntaktischen Zucker - die Optionen NEWSESSION und NESTEDSESSION, die ähnlich wie die gleichnamigen Operatoren funktionieren Erstellen von Aktionen, aber wie die Operatoren selbst, die mit Objekten arbeiten, muss der Entwickler keine neuen Aktionen erstellen und benennen. Zum Beispiel:
FORM teams
OBJECTS t=Team
// /
PROPERTIES (t) NEWSESSION NEW , EDIT , DELETE
OBJECTS p=Player
FILTERS team(p)=t
//
PROPERTIES (p) NEW , DELETE
;
Standardmäßig wird beim Bearbeiten eines Objekts das Bearbeitungsformular aufgerufen, das automatisch für die Klasse des übergebenen Formularobjekts generiert wird. Es ist jedoch häufig erforderlich, dieses Formular neu zu definieren (z. B. zusätzliche Informationen hinzuzufügen, das Design zu ändern usw.). Dazu reicht es aus, das erforderliche Bearbeitungsformular zu erstellen und anzugeben, dass es das Standardformular zum Bearbeiten von Objekten einer bestimmten Klasse ist:
FORM order ''
OBJECTS o = Order PANEL
PROPERTIES (o) date, number

OBJECTS d = OrderDetail
PROPERTIES (d) nameBook, quantity, price, NEW , DELETE
FILTERS order(d) = o

EDIT Order OBJECT o
;
Ebenso werden die Formulare zum Auswählen von Objekten einer bestimmten Klasse neu definiert.

Formgestaltung


Wie bei den meisten vorhandenen GUIs ist der Entwurf einer interaktiven Darstellung eines Formulars eine Hierarchie, deren Knoten Komponenten sind. Komponenten können wiederum sein:

  • Container - Komponenten, die andere Komponenten enthalten.
  • Grundkomponenten - grafische Darstellungen von Grundelementen: Tabellen, Eigenschaftenfenster, Filtergruppen usw.

Der Mechanismus zum Anordnen von Komponenten in Containern wiederholt im Wesentlichen das flexible CSS-Box-Layout (und ist damit im Web-Client implementiert), sodass wir nicht näher auf diesen Mechanismus eingehen werden.

Beachten Sie, dass das Design des Formulars normalerweise nicht von Grund auf neu erstellt wird (da es sehr zeitaufwändig ist). In der Regel wird ein Formularentwurf automatisch basierend auf der Struktur des Formulars erstellt, und der Entwickler ändert ihn dann nur geringfügig: Fügen Sie beispielsweise einen neuen Container hinzu und übertragen Sie vorhandene Komponenten darauf:

Beispiel für das Standardformulardesign
FORM myForm 'myForm'
OBJECTS myObject = myClass
PROPERTIES (myObject) myProperty1, myProperty2 PANEL
FILTERGROUP myFilter
FILTER 'myFilter' myProperty1(myObject)
;
Die Hierarchie der Container und Komponenten im Standarddesign sieht folgendermaßen aus:


FORM myForm ' '
OBJECTS u = CustomUser
PROPERTIES (u) name, NEW , DELETE

OBJECTS c = Chat
PROPERTIES (c) message, NEW , DELETE
FILTERS user(c) = u
;

DESIGN myForm {
NEW middle FIRST {
type = CONTAINERH ;
fill = 1 ; //
MOVE BOX (u);
MOVE BOX (c);
}
}
Screenshot erstellen


Form Design 2.0 (Reagieren)


Wenn Sie sich die interaktiven Darstellungen von Formularen in den obigen Screenshots (oder beispielsweise in einer Online-Demo) ansehen, sehen Sie, dass das aktuelle Formulardesign in der Benutzeroberfläche beispielsweise ziemlich asketisch ist. Dies war natürlich nie ein besonderes Problem für Informationssysteme, bei denen die Hauptnutzer Mitarbeiter oder Partner des Unternehmens sind, das diese Informationssysteme besitzt. Darüber hinaus können Sie mit dem aktuellen Formularentwurfsmechanismus trotz Askese sehr schwierige Fälle implementieren, z. B. POS:

Screenshot erstellen


Wenn es beispielsweise um SaaS B2B oder B2C geht, geschweige denn um Internetbanking, tauchen sofort Fragen auf, wie das Design ergonomischer gestaltet werden kann.

Zur Lösung dieses Problems wurde derzeit eine spezielle Javascript-Bibliothek entwickelt, deren Hauptaufgabe darin besteht, ein spezielles js-Objekt zu erstellen und zu aktualisieren, das Formulardaten enthält. Dementsprechend kann dieses Objekt als Zustand für die React-Komponente verwendet werden und dadurch jedes Design und jede zusätzliche Interaktivität der zu entwickelnden Form erzeugen. Zum Beispiel:

Beispielformular reagieren (auf Codesandbox)

Oder ein komplexeres Beispiel - mit Dropdown-Listen und Verwendung der REST-API (bzw. Stateless):

Reaktionsbeispiel mit Dropdown-Listen (auf Codesandbox)

Das Problem bei diesem Ansatz besteht zwar darin, dass die Formulare aus den obigen Beispielen weder in die allgemeine Plattformschnittstelle noch in den allgemeinen Steuerungsfluss von Aktionen eingebettet werden. Daher ist eine der unmittelbarsten Aufgaben bei der Entwicklung der Plattform die Übersetzung des Formularentwurfsmechanismus in das bei der Erstellung des Berichts verwendete Schema (gedruckte Präsentation):

  • Die Plattform generiert automatisch ein Reaktionsdesign basierend auf der Formularstruktur wie im obigen Beispiel.
  • Bei Bedarf kann der Entwickler es speichern und nach Belieben bearbeiten. Dementsprechend verwendet die Plattform dieses bearbeitete Design beim Öffnen des Formulars.

Darüber hinaus ermöglicht dieser Ansatz das Generieren von React Native-Formularen und damit das Erstellen nativer mobiler Anwendungen. Obwohl dieses Problem (mit nativen mobilen Anwendungen) noch nicht sehr tiefgreifend gelöst wurde.

Wir stellen zwar fest, dass der alte Entwurfsmechanismus ebenfalls unterstützt wird, da er für dieselben Geschäftsanwendungen seine Funktion perfekt erfüllt.

Formularereignisse


Formularereignisse sind der zweite Schlüsselmechanismus nach Domänenereignissen, der für die Bestimmung des Zeitpunkts der Ausführung von Aktionen verantwortlich ist.

Die Plattform verfügt über eine ganze Reihe verschiedener Formularereignisse, die sich aus bestimmten Benutzeraktionen ergeben. In diesem Artikel wird jedoch nur eines der am häufigsten verwendeten Ereignisse betrachtet - das CHANGE-Ereignis. Dieses Ereignis tritt auf, wenn der Benutzer einen Eigenschaftsänderungs- / Aktionsaufruf initiiert, z. B. durch Drücken einer beliebigen Nicht-Systemtaste auf der Tastatur, im Feld der zu ändernden Eigenschaft oder durch Klicken mit der Maus auf dieses Feld.

Für Ereignisse des Themenbereichs können Sie für Ereignisse des Formulars die Verarbeitung angeben - die Aktion, die ausgeführt wird, wenn das angegebene Ereignis eintritt. Beachten Sie, dass die meisten Formularereignisse bereits über eine Standardverarbeitung verfügen, die standardmäßig das vom Benutzer am meisten erwartete Verhalten implementiert (z. B. fordern Sie beim oben genannten CHANGE-Ereignis Eingaben vom Benutzer an und ändern Sie die Eigenschaft in den eingegebenen Wert). In der Praxis treten jedoch manchmal Situationen auf, in denen für ein Formularereignis eine bestimmte Verarbeitung angegeben werden muss, z.
changeQuantity (Order o, Book b) {
INPUT q = INTEGER DO { //
IF lastOrderDetail(o, b) THEN { // ,
IF q THEN //
quantity(OrderDetail d) <- q IF d = lastOrderDetail(o, b) WHERE order(d) = o AND book(d) = b; //
ELSE // -
DELETE OrderDetail d WHERE order(d) == o AND book(d) == b;
} ELSE
IF q THEN
NEW d = OrderDetail { //
order(d) <- o;
book(d) <- b;
quantity(d) <- q;
}
}
}

EXTEND FORM order
OBJECTS b = Book
PROPERTIES name(b) READONLY , quantity(o, b) ON CHANGE changeQuantity(o, b)
;
, – , ( , , , paste , ). . .


, , , , , , , , INPUT.

, , , , , , . Zum Beispiel:
FORM order
OBJECTS o = Order
PROPERTIES (o) customer ON CHANGE {
INPUT s = STRING DO {
customer(o) <- s;
IF s THEN
MESSAGE 'Customer changed to ' + s;
ELSE
MESSAGE 'Customer dropped' ;
}
}
;
, , :

  • ,
  • ( ),
  • ,
  • .

, INPUT – . (ASK):
DELETE Order o WHERE selected(o);
ASK ' ' + ( GROUP SUM 1 IF DROPPED (Order o)) + ' . ?' DO {
APPLY ;
}
(DIALOG) , , , , .

.


, . , , . , «» . , A B, A B, A A, B (A, B) B, A B ( «» ).

, , :

  • :
  • , , A B, A ( ).

Zum Beispiel:
FORM myForm 'myForm'
OBJECTS A, B SUBREPORT , C, D, E
PROPERTIES f(B, C), g(A, C)
FILTERS c(E) = C, h(B, D)
;


, , , , .


LGPL – JasperReports.

, JasperReports , . , :

  • «» ( , O1, O2, O3,… On, O2 – O1, O3 – O2 ..) ;
  • , .

«» , SUBREPORT ( , -):



:
FORM shipment
OBJECTS s=Shipment //
PROPERTIES (s) date, customer = nameCustomer, stock = nameStock // , ( customer) ( stock)
PROPERTIES total = ( GROUP SUM quantity(ShipmentDetail d)*price(d) IF shipment(d)=s) //
OBJECTS sd=ShipmentDetail //
FILTERS shipment(sd) = s //
PROPERTIES (sd) index, item = nameItem // , ( item)
PROPERTIES (sd) price, quantity // ,
PROPERTIES sum '' = (quantity(sd) * price(sd)) // - * ( sum)
;

run() {
// 12345
PRINT shipment OBJECTS s = ( GROUP MAX Shipment s IF number(s) = '12345' )
XLSX TO exportFile;
}



JasperReports (, lsFusion). , . , JasperSoft Studio.

, lsFusion- IDEA, Eclipse, ( Eclipse JasperReports ). IDEA , language injection, jrxml-, , , , , , . , , Eclipse GrammarKit autocomplete (, ), stub-, lazy chameleon- ( ), , . .


() :

  • (XML, JSON) – , () -.
  • (DBF, CSV, XLS) – - . parent, «» -.

, (- ), , , ( ). . , .


– XML, JSON. , , JSON ( XML ).

/ JSON , : JSON-, – , – . :

JSON
/ , / :

  • / : , .
  • X:
    • X , , . Dabei:
      • X ,
      • ( ) X.

, / :

 JSON  ::= { JSON  ,   /    } JSON  ,   /  ::= JSON  1 | JSON   1 | JSON   1 JSON  2 | JSON   2 | JSON   2 ... JSON  M | JSON   M | JSON   M JSON  ::= "   " :   JSON   ::= "  " : { JSON   ,   /  } JSON   ::= "  " : [ { JSON   ,   /  1 }, { JSON   ,   /  2 }, ... { JSON   ,   /  N }, ] 


:
GROUP money;

FORM shipment
OBJECTS dFrom= DATE , dTo= DATE
OBJECTS s=Shipment //
PROPERTIES (s) date, customer = nameCustomer, stock = nameStock // , ( customer) ( stock)
FILTERS dFrom <= date(s) AND date(s) <= dTo //
OBJECTS sd=ShipmentDetail //
FILTERS shipment(sd) = s //
PROPERTIES (sd) IN money index, item = nameItem, price, quantity // , ( item), , money
;

run() {
EXPORT shipment OBJECTS dFrom = 2019_02_20 , dTo = 2019_04_28 ; //
}
 { "s": [ { "date": "21.02.19", "sd": [ { "money": { "item": " 3", "quantity": 1, "price": 5, "index": 1 } } ], "stock": " 2", "customer": " 2" }, { "date": "15.03.19", "sd": [ { "money": { "item": " 1", "quantity": 1, "price": 5, "index": 1 } }, { "money": { "item": " 2", "quantity": 1, "price": 10, "index": 2 } }, { "money": { "item": " 3", "quantity": 1, "price": 15, "index": 3 } }, { "money": { "item": " 4", "quantity": 1, "price": 20, "index": 4 } }, { "money": { "item": "Milk", "quantity": 1, "price": 50, "index": 5 } } ], "stock": " 1", "customer": " 3" }, { "date": "04.03.19", "sd": [ { "money": { "item": " 1", "quantity": 2, "price": 4, "index": 1 } }, { "money": { "item": " 2", "quantity": 3, "price": 4, "index": 2 } }, { "money": { "item": " 1", "quantity": 2, "price": 5, "index": 3 } } ], "stock": " 1", "customer": " 2" }, { "date": "04.03.19", "sd": [ { "money": { "item": " 1", "quantity": 3, "price": 1, "index": 1 } }, { "money": { "item": " 2", "quantity": 2, "price": 1, "index": 2 } } ], "stock": " 1", "customer": " 2" }, { "date": "14.03.19", "sd": [ { "money": { "item": " 2", "quantity": 1, "price": 2, "index": 1 } } ], "stock": " 1", "customer": " 2" }, { "date": "17.04.19", "sd": [ { "money": { "item": " 2", "quantity": 5, "price": 6, "index": 1 } }, { "money": { "item": " 1", "quantity": 2, "price": 6, "index": 2 } } ], "stock": " 1", "customer": " 1" }, { "date": "21.02.19", "sd": [ { "money": { "item": " 3", "quantity": 1, "price": 22, "index": 1 } } ], "stock": " 2", "customer": " 1" }, { "date": "21.02.19", "sd": [ { "money": { "item": " 3", "quantity": 1, "price": 22, "index": 1 } } ], "stock": " 2", "customer": " 1" }, { "date": "20.02.19", "sd": [ { "money": { "item": " 3", "quantity": 1, "price": 22, "index": 1 } } ], "stock": " 2", "customer": " 1" } ] } 


, JSON JSON-. , , IDE JSON , – JSON. , ( , , JSON- ), . / JSON .


, :

  • .
  • – , .

, , , ( ). , , , / :
run() {
EXPORT XLSX FROM item = upper(name(Item i)), currentBalance(i, Stock s),
stock = name(s), barcode(i), salePrice(i)
WHERE (name(i) LIKE '%%' OR salePrice(i) > 10 ) AND currentBalance(i, s);
}
, SELECT SQL. , , , ( , ).

, , , – .


, , , :

  • – .
  • – : .
run(Genre g) {
SHOW booksByGenre OBJECTS g=g;
PRINT booksByGenre OBJECTS g=g;
EXPORT booksByGenre OBJECTS g=g;
}
– ( ) . .

(SHOW, DIALOG)


:

  • (WAIT) – , , , , .
  • (NOWAIT) – .

.

, :

  • (FLOAT) – .
  • (DOCKED) – System.forms.

, – .

, , (DIALOG). (, , ), , , .

, , (INPUT), ( ), , , ( ), , , ( ).
FORM booksByGenre
OBJECTS g = Genre PANEL
PROPERTIES (g) name
OBJECTS b = Book
PROPERTIES (b) name
FILTERS genre(b) = g
;

EXTEND FORM ordersByGenre
PROPERTIES (o) nameBook
ON CHANGE {
DIALOG booksByGenre OBJECTS g = g, b = book(o) INPUT DO
book(o) <- b;
}
;

(PRINT)


( ) , JasperReports : DOC, DOCX, XLS, XLSX, PDF, HTML, RTF , JasperReports. , , , , ( , ).

, - (PREVIEW), , / . , , .

(EXPORT, IMPORT)


, , , : XML, JSON, DBF, CSV, XLS, XLSX. .

, , , – . () , () , .

– , , « », :
  • .
  • ( , , , , , TRUE f(a) = b – f(a) b)

TRUE ( , , 0 , .., , , ).
// ,
inn = DATA LOCAL BPSTRING [ 9 ] (Shipment);
barcode = DATA LOCAL BPSTRING [ 13 ] (ShipmentDetail);

FORM shipments
OBJECTS s=Shipment EXTID 'shipments' // EXTID s, shipments
PROPERTIES (s) number, date, inn
OBJECTS sd=ShipmentDetail EXTID 'detail' // EXTID sd, detail
FILTERS shipment(sd) = s // shipment detail
PROPERTIES (sd) barcode, price, quantity
;

run() {
FOR jsonFile = JSONFILE ( '\{ shipments : [ ' + // jsonFile / run, {} escape'
' \{number : "13423", date : "01.01.2019", inn : "2", detail : [\{ barcode : "141", quantity : 5, price : 10 \}, \{ barcode : "545", quantity : 2, price : 11 \}] \},' +
' \{number : "12445", date : "01.02.2019", inn : "1", detail : [\{ barcode : "13", quantity : 1, price : 22 \}] \} ]\}' )
DO {
IMPORT shipments FROM jsonFile; //
FOR BPSTRING [ 9 ] inn = inn(Shipment s) DO { // inn
customer(s) <- legalEntityINN(inn); // INN
stock(s) <- GROUP MAX st AS Stock; // - ( id)
}
FOR barcode(Item item) = barcode(ShipmentDetail sd) DO //
item(sd) <- item;

APPLY ;
exportString() <- IF canceled() THEN applyMessage() ELSE ' ' ;
}
}


, , . , , , . . ( ), .

- , ( ). , , ( ). .


. , — .

– , . , , . , , .



.



100x100 . , , . , «» . , ( ). , . , .

. , - , , .

:
  • , – , , .
  • – forms, log, status, root, toolbar, tree, (, root, , )
FORM items;
FORM stocks;
FORM legalEntities;
FORM shipments;
hello() { MESSAGE 'Hello world' ; }
hi() { MESSAGE 'Hi' ; }

NAVIGATOR {
NEW FOLDER catalogs '' WINDOW toolbar { // ,
NEW items; // - items,
}
catalogs { //
NEW FORM stocksNavigator '' = stocks; // - stocksNavigator stocls catalogs
NEW legalEntities AFTER items; // - legalEntities catalogs items
NEW shipments;
}
NEW FOLDER documents '' WINDOW toolbar { // ,
// root,
//
NEW ACTION hi; // -
NEW ACTION h=hello; // -
MOVE shipments BEFORE h; // shipments catalogs document hello
}
}


, – , , , , , ERP-. , , « », : ? ? ? , -, lsFusion language-based ( SQL ABAP), library-based ( Java 1C) / . , , – domain-specific , . -, , , , . : , , , . , , , ( ).

. – , :

  • : , , , , , ;
  • : , .

, :

  • . «» : , , / . , , , , , , .
  • . control flow . , – .
  • SQL ( ORM). , , , .

Fazit


, , (, , , , tutorial, , , ). , , ( ) «», , lsFusion.

, , – . , . , , « . .», , ( - ).

. : « ». , . , , lsFusion SQL-. , , , – , - , . , SQL- ( ). , . , , ( , ), , , . «?», « ...?» «?».

UPD: .

Source: https://habr.com/ru/post/de460141/


All Articles