我们正在建立一个界面,用于通过选择输入文档

图片

在各种业务应用程序中,经常出现文档输入的任务。 通常,文档由标题和几行组成,每行都引用某个对象(例如,产品)。 大多数情况下,使用常规表将记录输入文档中,用户可以在其中添加和删除行以及更改其内容。

但是,在某些情况下,这种方案并不总是对用户方便。 在本文中,我将告诉您如何使用选择产品的技术来构建方便的用户界面。

挑战赛


通常,在为用户输入文档时,对可以添加到其中的对象集有限制。 在这种情况下,对于用户而言,显示具有此类对象的列表并具有将它们快速包括(和排除)到文档中的能力是合乎逻辑的。 在列中,对于每个对象,还可以方便地显示决定是否需要将其包含在文档中所需的数据。 最后,通常需要与对象一起输入其数量。

让我们考虑在业务应用程序中经常发现的三种类型的文档:

  1. 采购订单 。 在这样的文档中,用户应该显示所有可从供应商处订购的商品清单。 在列中,可以方便地显示当前余额,一定时间间隔内的销售额,订购的买卖数量。
  2. 销售订单 。 在这里,最常见的是,显示了所选仓库的余额上可出售给所选客户的货物清单。 还应显示当前价格。
  3. 余额变动 。 如果与实际金额有任何差异,本文档用于调整当前余额。 通常会在选择中显示所有产品,并能够输入其中任何一个的实际余额。 同时,将产品添加到单据中,其数量等于实际余额与当前余额之间的差额。

解决方案


接下来,我将展示如何基于开放和免费的lsFusion平台快速轻松地实现此逻辑。 例如,让我们创建用于输入采购订单的逻辑。

首先,通过标准CRUD界面添加产品指南:
CLASS Product '' ;
name '' = DATA STRING [ 50 ] (Product);

FORM product ''
OBJECTS p = Product PANEL
PROPERTIES (p) name

EDIT Product OBJECT p //
;

FORM products ''
OBJECTS p = Product
PROPERTIES (p) READONLY name
PROPERTIES (p) NEWSESSION NEW , EDIT , DELETE

LIST Product OBJECT p // ,
;

NAVIGATOR {
NEW products;
}

我们创建了供应商的概念,并通过编辑的形式使我们有机会选择与其合作的产品:
CLASS Supplier '' ;
name '' = DATA STRING [ 50 ] (Supplier);

in '' = DATA BOOLEAN (Supplier, Product); // TRUE,

FORM supplier ''
OBJECTS s = Supplier PANEL
PROPERTIES (s) name

OBJECTS p = Product //
PROPERTIES in(s, p), name(p) READONLY //

EDIT Supplier OBJECT s
;

FORM suppliers ''
OBJECTS s = Supplier
PROPERTIES (s) READONLY name
PROPERTIES (s) NEWSESSION NEW , EDIT , DELETE

LIST Supplier OBJECT s
;

NAVIGATOR {
NEW suppliers;
}

用以下行声明顺序逻辑:
CLASS Order '' ;
date '' = DATA DATE (Order);
number '' = DATA INTEGER (Order);

supplier '' = DATA Supplier (Order);
nameSupplier '' (Order o) = name(supplier(o));

CLASS OrderDetail ' ' ;
order '' = DATA Order (OrderDetail) NONULL DELETE ;

将产品和数量添加到生产线:
product '' = DATA Product (OrderDetail);
nameProduct '' (OrderDetail d) = name(product(d));

quantity '-' = DATA NUMERIC [ 14 , 3 ] (OrderDetail);

我们直接进行所需的订单编辑表单的构建。 首先,添加订单本身及其行:
FORM order ''
OBJECTS o = Order PANEL
PROPERTIES (o) date, number, nameSupplier

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

EDIT Order OBJECT o
;

因此,我们获得了一个用于通过添加和删除来处理订单行的标准接口。
接下来,我们将需要的选择功能添加到此表单中。 为此,首先在表单上创建一个包含所有商品列表的对象,在该对象中,我们仅筛选允许从选定供应商订购的商品:
EXTEND FORM order
OBJECTS p = Product
PROPERTIES name(p) READONLY
FILTERS in(supplier(o), p) //
;

我们设置设计,以便将订单行和选择显示为一个容器的标签:
DESIGN order {
OBJECTS {
NEW pane { //
fill = 1 ; //
type = TABBED ; // ,
MOVE BOX (d); //
MOVE BOX (p) { //
caption = '' ;
}
}
}
}

我们构建辅助属性,以供用户在相应列中显示和输入数量:
quantity '-' (Order o, Product p) =
GROUP SUM quantity(OrderDetail d) BY order(d), product(d);
lastOrderDetail ' ' (Order o, Product p) =
GROUP LAST OrderDetail d ORDER d BY order(d), product(d);

第一个属性在本文档中考虑此订单和产品的数量。 第二个找到最后一行(用户可以使用一个产品输入几行)。
接下来,我们创建一个动作,该动作将处理用户在选择选项卡的相应列中输入值的过程:
changeQuantity ' -' (Order o, Product p) {
INPUT q = NUMERIC [ 14 , 3 ] DO { //
IF lastOrderDetail(o, p) THEN { // ,
IF q THEN //
quantity(OrderDetail d) <- q IF d = lastOrderDetail(o, p)
WHERE order(d) = o AND product(d) = p; //
ELSE // -
DELETE OrderDetail d WHERE order(d) = o AND product(d) == p;
} ELSE
IF q THEN
NEW d = OrderDetail { //
order(d) <- o;
product(d) <- p;
quantity(d) <- q;
}
}
}

最后,我们在表单中添加一列,指示当用户尝试更改其值时应执行的操作:
EXTEND FORM order
PROPERTIES (o, p) quantity ON CHANGE changeQuantity(o, p)
;

剩下的只是绘制带有订单列表的表单并将其添加到导航器中:
FORM orders ''
OBJECTS o = Order
PROPERTIES (o) READONLY date, number
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE
;

NAVIGATOR {
NEW orders;
}

生成的表单将如下所示:

图片

对任何选项卡所做的任何更改都会自动反映到其他选项卡上。

在实际的ERP系统中,显着增加了更多的列和其他元素。 例如,在这些实现之一中它看起来像这样:

图片


让我们看看如何在其他业务应用程序中实现此功能。

1C


在1C的不同配置中,选择逻辑具有某些差异,但原理或多或少是相同的。 在文档编辑表单上有一个“选择”按钮,它会弹出一个对话框,其中包含商品选择:

图片

在此对话框中,您可以选择货物,如下所示:

图片

这种机制至少有两个不便之处。

首先,为了将产品数量添加到文档中(大多数情况下用户已经知道他要添加的数量),您必须首先双击产品,将其添加到行中,然后在行中更改数量。 此外,用户不会在产品列表中看到该产品是否已经添加以及添加多少。 此外,这种方案“占用”了额外的空间,因为您必须在一个屏幕上显示两个表而不是一个表。

其次,在将行直接添加到文档后,如果再次单击“选择”按钮,则选择将“从头开始”。 它不会在底部表格中显示任何行,并且在重新选择时,尚不清楚文档中已经有什么,没有什么。 在构建界面时,它还违反了重要规则之一:如果用户输入错误,则需要给他机会返回并更正错误。 事实证明,他将无法返回与在文档上按添加按钮之前具有相同数据的商品选择。

但是,可以在1C中实现上述方案,但是由于某些原因,在具有演示站点的站点上可用的典型配置中,使用了另一个配置。

Microsoft Dynamics 365


作为解决方案,我选择了零售(仅在其中找到了类似的功能, 网址https://trials.dynamics.com )。 在其中,您可以通过两种方式在“采购订单”表单上调用选择:

图片

第一个按钮是根据1C方案实现的(尽管列的数量要少得多),因此我不再赘述。

第二个按钮将弹出一个对话框,其中列出了可以在栏中输入数量的产品。 但这是以非常特殊的方式完成的。

首先,默认情况下,仅在其中显示产品代码(即使没有名称)。 当然,我知道您可以创建扩展并在其中包含其他列,但是在基本版本中看到此行为有点奇怪。

其次,微软显然对这种设计感到震惊,由于某种原因,他们在滚动数据,处理技巧和事件的正常处理方面得分很高。 看起来像这样:

图片

在正常的键盘操作中,当重新读取数据时,当前系列会不断切换。 同时,只有在等待所有事件处理后才能开始输入,否则根本不会输入数量,或者输入的序列错误。 真正的用户如何使用它仍然是我的一个谜。 显然,很少有人专门使用此功能。 好吧,或者这是演示的局限性,但是在操作中一切正常。

结论


通过单独的选择选项卡描述的文档输入方案深受用户欢迎。

在实践中,此概念可能会以各种方式变得复杂。 例如,代替产品列表,而是显示商品列表,该商品列表能够为各个特征输入不同的数量。 或者,在其中一个文档中,行中有仓库,并且需要在列中为每个仓库设置数量。

例如,可以在同一React中实现这种方案,使用文档的当前行作为状态,并在两个不同的选项卡中以两个组件显示它。 但应记住,表中可能有很多商品条目,您将必须实施所谓的“无限滚动”。 另外,建议向用户添加对列表中的产品进行排序和筛选的功能(并且这必须在服务器上而不是在客户端上完成,以免在此处拖出多余的数据)。 对于开发人员来说,所有这一切都变得不平凡。

在lsFusion平台中,此功能是开箱即用的,仅需要上述代码即可实现。 您可以尝试其工作方式,如果需要,可以在相应页面上在线修改代码。 这是完整的源代码,可以将其插入“平台”选项卡上,然后单击“播放”:

源代码
CLASS Product '' ;
name '' = DATA STRING [ 50 ] (Product);

FORM product ''
OBJECTS p = Product PANEL
PROPERTIES (p) name

EDIT Product OBJECT p //
;

FORM products ''
OBJECTS p = Product
PROPERTIES (p) READONLY name
PROPERTIES (p) NEWSESSION NEW , EDIT , DELETE

LIST Product OBJECT p // ,
;

NAVIGATOR {
NEW products;
}

CLASS Supplier '' ;
name '' = DATA STRING [ 50 ] (Supplier);

in '' = DATA BOOLEAN (Supplier, Product); // TRUE,

FORM supplier ''
OBJECTS s = Supplier PANEL
PROPERTIES (s) name

OBJECTS p = Product //
PROPERTIES in(s, p), name(p) READONLY //

EDIT Supplier OBJECT s
;

FORM suppliers ''
OBJECTS s = Supplier
PROPERTIES (s) READONLY name
PROPERTIES (s) NEWSESSION NEW , EDIT , DELETE

LIST Supplier OBJECT s
;

NAVIGATOR {
NEW suppliers;
}

CLASS Order '' ;
date '' = DATA DATE (Order);
number '' = DATA INTEGER (Order);

supplier '' = DATA Supplier (Order);
nameSupplier '' (Order o) = name(supplier(o));

CLASS OrderDetail ' ' ;
order '' = DATA Order (OrderDetail) NONULL DELETE ;

product '' = DATA Product (OrderDetail);
nameProduct '' (OrderDetail d) = name(product(d));

quantity '-' = DATA NUMERIC [ 14 , 3 ] (OrderDetail);

FORM order ''
OBJECTS o = Order PANEL
PROPERTIES (o) date, number, nameSupplier

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

EDIT Order OBJECT o
;

EXTEND FORM order
OBJECTS p = Product
PROPERTIES name(p) READONLY
FILTERS in(supplier(o), p) //
;

DESIGN order {
OBJECTS {
NEW pane { //
fill = 1 ; //
type = TABBED ; // ,
MOVE BOX (d); //
MOVE BOX (p) { //
caption = '' ;
}
}
}
}

quantity '-' (Order o, Product p) =
GROUP SUM quantity(OrderDetail d) BY order(d), product(d);
lastOrderDetail ' ' (Order o, Product p) =
GROUP LAST OrderDetail d ORDER d BY order(d), product(d);

changeQuantity ' -' (Order o, Product p) {
INPUT q = NUMERIC [ 14 , 3 ] DO { //
IF lastOrderDetail(o, p) THEN { // ,
IF q THEN //
quantity(OrderDetail d) <- q IF d = lastOrderDetail(o, p)
WHERE order(d) = o AND product(d) = p; //
ELSE // -
DELETE OrderDetail d WHERE order(d) = o AND product(d) == p;
} ELSE
IF q THEN
NEW d = OrderDetail { //
order(d) <- o;
product(d) <- p;
quantity(d) <- q;
}
}
}

EXTEND FORM order
PROPERTIES (o, p) quantity ON CHANGE changeQuantity(o, p)
;

FORM orders ''
OBJECTS o = Order
PROPERTIES (o) READONLY date, number
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE
;

NAVIGATOR {
NEW orders;
}

Source: https://habr.com/ru/post/zh-CN464487/


All Articles