组件数据交互基础(v4)

阅读之前

你应该:

组件数据交互概述

数据结构设计

数据结构分为三大类,列表(List)对象(Object)以及弹出层(Popup)

  • 列表(List):用于多条数据的展示,主要包括搜索(用户端)自定义条件(产品端)排序分页数据选中数据提交数据校验功能。
  • 对象(Object):用于单条数据的展示,主要包括数据提交数据校验功能。
  • 弹出层(Popup):用于在一块独立的空间展示对应类型的数据。

数据结构与对于的内置视图类型:

  • 列表(List):表格视图(TABLE)画廊视图(GALLERY)
  • 对象(Object):表单视图(FORM)详情视图(DETAIL)

数据交互设计原则

组件与组件之间的结构关系是独立的,组件与组件之间的数据是关联的。因此,数据交互整体采用“作用域隔离(View),行为互通(CallChaining),数据互通(ActiveRecords)”这样的基本原则进行设计。实现时,围绕不同视图类型定义了一类数据结构所需的基本属性。

在弹出层进行设计时,使用Submetadata的方式,将包括弹出层在内的所有组件包含在内,以形成新的作用域。

通用属性及方法

属性

  • rootData:根数据源
  • dataSource:当前数据源
  • activeRecords:当前激活数据源

为了在实现时包含所有数据结构,我们统一采用ActiveRecord[]类型为所有数据源的类型,这些数据源在不同类型的视图中表示不同的含义:

  • 列表(List):dataSource为列表当前数据源,activeRecords为列表中被选中的数据。特别的,showDataSource为当前展示的数据源,它是dataSource经过搜索、排序、分页等处理后的数据源,也是我们在组件中真正使用的数据源。
  • 对象(Object):daraSourceactiveRecords总是完全一致的,且长度永远为1。因此我们有时也在组件中定义formData属性,并提供默认实现:this.activeRecords?.[0] || {}

方法

  • reloadDataSource:重载当前数据源
  • reloadActiveRecords:重载当前激活数据源

由于底层实现并不能正确判断当前使用的数据类型,因此我们无法采用统一标准的数据源修改方法,这时候需要开发者们自行判断。

重载列表数据源
cosnt dataSource: ActiveRecord[] = 新的数据源
// 重载数据源
this.reloadDataSource(dataSource);
// 重置选中行
this.reloadActiveRecords([]);
重载表单数据源
cosnt dataSource: ActiveRecord[] = 新的数据源(数组中有且仅有一项)
// 重载数据源
this.reloadDataSource(dataSource);
// 此处必须保持相同引用
this.reloadActiveRecords(dataSource);

内置CallChaining(链式调用)

在自动化渲染过程中,我们通常无法明确知道当前组件子组件交互的具体情况,甚至我们在定义当前组件时,并不需要关心(某些情况下可能无法关心)子组件的具体情况。这也决定了我们无法在任何一个组件中完整定义所需的一切功能。

为了保证组件行为的一致性,我们需要某些行为在各个组件的实现需要做到组件自治。以表格视图为例:当view标签在挂载时,我们无法确定应该怎样正确的加载数据,因此,我们需要交给一个具体的element标签来完成这一功能。当element标签对应的组件发生变化时,只需按照既定的重载方式将数据源提交给view标签即可。

除了保证组件行为的一致性外,我们不能完全的信任第三方框架对组件生命周期的处理顺序。因此,我们还需要对组件行为进行进一步的有序处理。以表格视图为例:我们希望搜索视图(SEARCH)的处理总是在加载数据前就处理完成的,这样将可以保证我们加载数据可以正确处理搜索条件,而这一特性并不随着模板结构的变化而发生变化。

平台内置的CallChaining
  • mountedCallChaining:挂载时钩子;
  • refreshCallChaining:刷新时钩子;
  • submitCallChaining:提交时钩子;
  • validatorCallChaining:验证时钩子;
优先级常量
  • VIEW_WIDGET_PRIORITY(0):视图组件优先级
  • FETCH_DATA_WIDGET_PRIORITY(100):数据提供者组件优先级
  • SUBVIEW_WIDGET_PRIORITY(200):子视图组件优先级

未设置优先级的hook将最后执行,在通常情况下,你无需关心优先级的问题。

注意事项
  • CallChaining通常不需要手动初始化,仅需通过inject方式获取即可。
  • CallChaining的hook/unhook方法需要在组件生命周期的mounted/unmounted分别执行,如无特殊情况,一般通过this.path作为挂载钩子的唯一键。
字段组件中使用mountedCallChaing
@Widget.Reactive()
@Widget.Inject()
protected mountedCallChaining: CallChaining | undefined;

protected mountedProcess() {
  // 挂载时处理
}

protected mounted() {
  super.mounted();
  this.mountedCallChaining?.hook(this.path, () => {
    this.mountedProcess();
  });
}

protected unmounted() {
  super.unmounted();
  this.mountedCallChaining?.unhook(this.path);
}

字段组件mountedCallChaing并不是必须的,因此我们未进行内置处理。

一般的,当视图数据被加载完成时,字段组件formDatavalue等属性,将通过响应式自动获取对应的值,因此在大多数情况下是不需要使用这一特性的。

当我们需要对字段获取的值做进一步初始化处理时,我们将需要使用这一特性。例如TreeSelect组件,必须在初始化时填充树下拉所需的结构化数据,这样才能正确展示对应的值。

字段组件mounted方法被执行时,我们还未执行视图数据加载,因此,在我们无法在mounted方法中操作formDatavalue等属性,只有在mountedCallChainingview标签执行时,按照执行顺序,此时字段的mountedChaining将在视图数据被加载完成后执行。

数据源持有者和数据源提供者

在设计上,我们通常将view标签设计为数据源持有者,将element标签设计为数据源提供者

原则上,在一个视图中有且仅有一个数据源提供者。

即:当一个element标签的实现组件通过reloadDataSource方法view标签设置数据源,我们就称该实现组件为当前view标签数据源提供者view标签数据源持有者

provider/inject

阅读该章节需要理解vue的依赖注入原理

在实现上,我们通过provider/inject机制将上述通用属性/方法进行交替处理,就可以实现根据模板定义的结构进行隔离和共享功能。

例如dataSource属性的实现:

/**
 * 上级数据源
 * @protected
 */
@Widget.Reactive()
@Widget.Inject('dataSource')
protected parentDataSource: ActiveRecord[] | undefined;

/**
 * 当前数据源
 * @protected
 */
@Widget.Reactive()
private currentDataSource: ActiveRecord[] | null | undefined;

/**
 * 提供给下级的数据源
 * @protected
 */
@Widget.Reactive()
@Widget.Provide()
public get dataSource(): ActiveRecord[] | undefined {
  return this.currentDataSource || this.parentDataSource;
}

不足的是,由于provider/inject机制特性决定,通过provider提供的属性和方法,在某些情况下可能会进行穿透,导致组件通过inject获取的属性和方法并非是我们所期望的那样,因此,我们仍然需要进行一些特殊的处理,才能正确的处理子视图的数据交互,这一点在对象(Object)类型的视图中会详细介绍。

运行时上下文(metadataHandle/rootHandle)

在之前的文章中,我们知道前端的字段/动作组件渲染和后端元数据之间是密不可分的。

在数据交互方面,后端元数据对于字段类型的定义,将决定从API接口中获取的字段、数据类型和格式,以及通过API接口提交数据到后端时的字段、数据类型和格式

数据类型和格式可以通过field标签data属性,获取到经过后端编译的相关字段元数据。

那么,我们该如何决定,当数据提供者向后端发起请求时,应该获取哪些字段呢?

因此,我们设计了RuntimeContext机制,并通过metadataHandle/rootHandle机制,在任何一个组件都可以通过view标签正确获取已经实现隔离的运行时上下文机制。

以表单视图为例,我们来看这样一个经过合并后的完整视图模板:

(以下模板所展示的并非实际的运行时的结果,而是为了方便描述所提供的完整视图模板)

<view type="FORM">
    <element widget="actions">
        <action name="create" invisible="activeRecord.id" />
        <action name="update" invisible="!activeRecord.id" />
    </element>
    <element widget="fields">
        <field data="id" invisible="true" />
        <field data="code" />
        <field data="name" />
        <field data="relationOne" widget="Form">
            <view type="FORM">
                <element widget="form">
                    <field data="id" invisible="true" />
                    <field data="code" />
                    <field data="name" />
                </element>
            </view>
        </field>
        <field data="relationMany" widget="Table">
            <view type="TABLE">
                <element widget="actionBar">
                    <action name="openCreateDialog">
                        <view type="FORM">
                            <element widget="fields">
                                <field data="id" invisible="true" />
                                <field data="code" />
                                <field data="name" />
                            </element>
                        </view>
                    </action>
                </element>
                <element widget="table">
                    <field data="id" invisible="true" />
                    <field data="code" />
                    <field data="name" />
                    <element widget="rowActions">
                        <action name="openEditDialog">
                            <view type="FORM">
                                <element widget="fields">
                                    <field data="id" invisible="true" />
                                    <field data="code" />
                                    <field data="name" />
                                </element>
                            </view>
                        </action>
                    </element>
                </element>
            </view>
        </field>
    </element>
</view>

其中:

  • relationOne字段:代表M2O字段,它使用Form组件将字段展开为子表单视图。(O2O类型基本一致)
  • relationMany字段:代表O2M字段,它使用Table组件将字段展开为子表格视图。(M2M类型基本一致)
    • openCreateDialog:代表打开一个创建弹窗,它是一个上下文类型为上下文无关的跳转动作。
    • openEditDialog:代表打开一个编辑弹窗,它是一个上下文类型为单行的跳转动作。

PS:这里我们关注的是组件之间的数据交互,至于动作相关内容,我们会在其他文章中做进一步介绍。在这里我们只需要了解,当按钮的上下文类型为上下文无关时,该按钮将不会携带任何数据到下一个视图中;当按钮的上下文类型为单行时,该按钮将携带activeRecords[0]的数据到下一个视图中。

通过这个视图模板,我们将构建出如下图所示的RuntimeContext结构:

image.png

``` mermaid
graph TD
metadataHandle-1("metadataHandle-1(ViewAction)") ---> rootHandle-1("rootHandle-1(view type=#quot;FORM#quot;)")

rootHandle-1 ---> metadataHandle-2 & metadataHandle-3

metadataHandle-2("metadataHandle-2(field data=#quot;relationOne#quot;)") ---> rootHandle-2("rootHandle-2(view type=#quot;FORM#quot;)")
metadataHandle-3("metadataHandle-3(field data=#quot;relationMany#quot;)") ---> rootHandle-3("rootHandle-3(view type=#quot;TABLE#quot;)")

rootHandle-3 ---> metadataHandle-4 & metadataHandle-5

metadataHandle-4("metadataHandle-4(action name=#quot;openCreateDialog#quot;)") ---> rootHandle-4("rootHandle-4(view type=#quot;FORM#quot;)")
metadataHandle-5("metadataHandle-5(action name=#quot;openEditDialog#quot;)") ---> rootHandle-5("rootHandle-5(view type=#quot;FORM#quot;)")
```

由此可见,我们的metadataHandle可能通过页面入口(ViewAction)提供,也可能通过字段(field标签)提供,还可能通过动作(action标签)提供。无一例外的是,所有的view标签都将生成一个与之对应的rootHandle

在编码过程中,我们可以通过this.metadataRuntimeContextthis.rootRuntimeContext获取到对应的运行时上下文。前端运行时上下文API文档

列表(List)数据交互

对于列表(List)数据结构来说,我们目前提供了两种具体的视图:表格视图(TABLE)画廊视图(GALLERY),这两种视图分别对应不同的数据展示形态。

  • 表格视图(TABLE):字段代表表格中的列(Column),每一列的数据使用相同方式展示,无法使用布局特性。
  • 画廊视图(GALLERY):使用list - item形式进行渲染,每一个item可以通过DSL描述其布局特性。

特别的是,搜索视图(SEARCH)是对列表(List)数据结构提供搜索(用户端)相关功能的子视图,其独立存在于页面中是没有意义的。

默认表格视图(TABLE)

<view type="TABLE">
    <pack widget="group">
        <view type="SEARCH">
            <element widget="search" slot="search" />
        </view>
    </pack>
    <pack widget="group" slot="tableGroup">
        <element widget="actionBar" slot="actionBar">
            <xslot name="actions" />
        </element>
        <element widget="table" slot="table">
            <element widget="expandColumn" slot="expandRow" />
            <xslot name="fields" />
            <element widget="rowActions" slot="rowActions" />
        </element>
    </pack>
</view>

在之前的文章中,我们了解了布局和标签的基本概念,为了能更好的说明数据交互相关的特征,我们将上述视图进行简化,仅留下与数据交互相关的标签。

<view type="TABLE">
    <view type="SEARCH">
        <element widget="search" slot="search" />
    </view>
    <element widget="actionBar" slot="actionBar">
        <xslot name="actions" />
    </element>
    <element widget="table" slot="table">
        <xslot name="fields" />
        <element widget="rowActions" slot="rowActions" />
    </element>
</view>

在这个视图中,我们可以获得如下信息:

  • 主视图为表格(TABLE)视图。
  • 包含一个搜索(SEARCH)子视图。
  • 包含两个主要的element组件widget="actionBar"widget="table"
  • widget="table"中内置了一个element组件widget="rowActions"

在我们内置的组件实现中,widget="table"这个组件通过调用后端接口,为整个视图提供数据源。

组件挂载时序图

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant SearchView as SearchView("view type=#quot;SEARCH#quot;")
participant Search as SearchWidget("element widget=#quot;search#quot;")

participant ActionBar as ActionBarWidget("element widget=#quot;actionBar#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")
participant RowActionBar as RowActionBarWidget("element widget=#quot;rowActions#quot;")

TableView ->> TableView : before mount
TableView ->> SearchView : before mount
SearchView ->> Search : before mount
TableView ->> ActionBar : before mount
TableView ->> Table : before mount
Table ->> RowActionBar : before mount

Search ->> SearchView : mounted
SearchView ->> TableView : mounted
ActionBar ->> TableView : mounted
RowActionBar ->> Table : mounted
Table ->> TableView : mounted
TableView ->> TableView : mounted

TableView ->> TableView : mountedCallChaing hook (VIEW_WIDGET_PRIORITY)

TableView ->> SearchView : mountedCallChaing hook (VIEW_WIDGET_PRIORITY)
SearchView ->> Search : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)

TableView ->> Table : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)

```

在上图中,我们可以看到,mountedCallChaining是在所有组件全部渲染并挂载完成后,通过最上层的view标签进行调用的,并且按照一定的优先级顺序执行了每个组件实现的挂载钩子函数

组件数据源加载

widget="search"组件执行了挂载钩子函数时,将从url参数中获取所需的searchBodysearchCondition属性,并通过flushSearchParameters方法将这两个参数提交到表格视图(TABLE)

widget="table"组件执行了挂载钩子函数时,将执行加载数据相关功能,并通过reloadDataSourcereloadActiveRecords方法对数据源进行向上提交。

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant SearchView as SearchView("view type=#quot;SEARCH#quot;")
participant Search as SearchWidget("element widget=#quot;search#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")

TableView ->> SearchView : mountedCallChaing hook (VIEW_WIDGET_PRIORITY)
SearchView ->> Search : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)
Search ->> Search : resolve url parameters
Search ->> SearchView : reloadActiveRecords
Search ->> TableView : flushSearchParameters

TableView ->> Table : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)
Table ->> Table : mounted process (call api)
Table ->> TableView : reloadDataSource
Table ->> TableView : reloadActiveRecords

```

用户行为触发的数据交互

这里列举了一些列表(List)常用的数据交互时序图,用于帮助大家对数据交互的整体逻辑可以有更清晰的理解。

点击搜索

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant SearchView as SearchView("view type=#quot;SEARCH#quot;")
participant Search as SearchWidget("element widget=#quot;search#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")

Search ->> TableView : flushSearchParameters
Search ->> SearchView : refreshCallChaining (call)
SearchView ->> TableView : refreshCallChaining (call)

TableView ->> Table : refreshCallChaining hook (FETCH_DATA_WIDGET_PRIORITY)
Table ->> Table : refresh process (call api)
Table ->> TableView : reloadDataSource
Table ->> TableView : reloadActiveRecords

```

排序/分页

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")

Table ->> Table : refresh process (call api)
Table ->> TableView : reloadDataSource
Table ->> TableView : reloadActiveRecords

```

表格勾选(table checkbox/radio)

image.png

``` mermaid
sequenceDiagram

participant TableView as TableView("view type=#quot;TABLE#quot;")

participant Table as TableWidget("element widget=#quot;table#quot;")

Table ->> TableView : reloadActiveRecords

```

对象(Object)数据交互

对于对象(Object)数据结构来说,我们目前提供了两种具体的视图:表单视图(FORM)详情视图(DETAIL),这两种视图分别对应不同的数据展示形态。

  • 表单视图(FORM):主要用于数据的填写和提交;可以通过DSL描述其布局特性。
  • 详情视图(DETAIL):主要用于数据的展示,所有字段强制为只读态(与表单的只读态有所不同);可以通过DSL描述其布局特性。

特别的是,表单视图(FORM)详情视图(DETAIL)在对子视图的处理上并不完全相同。主要体现在数据提交类型(submitType)关联关系更新类型(relationUpdateType)这两个属性的处理上。

数据提交类型(submitType)
/**
 * 数据提交类型
 */
export enum SubmitType {
  /**
   * <h3>默认</h3>
   * <p>
   * 基础字段使用全量提交,关联关系字段使用关联关系提交
   * </p>
   */
  default = 'default',
  /**
   * 不提交
   */
  none = 'none',
  /**
   * 关联关系字段关系提交(仅对关联关系字段有效)
   */
  relation = 'relation',
  /**
   * 关联关系字段增量提交(仅对关联关系字段有效)
   */
  increment = 'increment',
  /**
   * 全量提交
   */
  all = 'all'
}
关联关系更新类型(relationUpdateType)
/**
 * 关联关系数据更新类型
 */
export enum RelationUpdateType {
  /**
   * <h3>默认</h3>
   * <p>
   * 默认根据数据提交类型进行自动识别
   * </p>
   */
  default = 'default',
  /**
   * 使用特定接口进行差量更新(关联关系字段强制使用增量提交)
   */
  diff = 'diff',
  /**
   * 使用batch接口进行差量更新(关联关系字段强制使用增量提交)
   */
  batch = 'batch',
  /**
   * 全量更新
   */
  all = 'all'
}

下面分别列举了一些字段组件在不同视图中的默认功能。

表单视图(FORM)
组件 (widget) 一对一(O2O) 多对一(M2O) 一对多(O2M) 多对多(M2M)
Table / / 前端搜索、分页、排序
submitType="all"
relationUpdateType="all"
前端搜索、分页、排序
submitType="relation"
relationUpdateType="all"
Form submitType="all"
relationUpdateType="all"
submitType="all"
relationUpdateType="all"
/ /
Select submitType="relation"
relationUpdateType="all"
submitType="relation"
relationUpdateType="all"
submitType="relation"
relationUpdateType="all"
submitType="relation"
relationUpdateType="all"
详情视图(DETAIL)
组件 (widget) 一对一(O2O) 多对一(M2O) 一对多(O2M) 多对多(M2M)
Table / / 后端搜索、分页、排序
不支持数据提交
后端搜索、分页、排序
不支持数据提交
Form 仅用于查看
submitType="relation"
relationUpdateType="all"
仅用于查看
submitType="relation"
relationUpdateType="all"
/ /
Select 仅用于查看
submitType="relation"
relationUpdateType="all"
仅用于查看
submitType="relation"
relationUpdateType="all"
仅用于查看
submitType="relation"
relationUpdateType="all"
仅用于查看
submitType="relation"
relationUpdateType="all"

默认表单视图(FORM)

<view type="FORM">
    <element widget="actionBar" slot="actionBar">
        <xslot name="actions" />
    </element>
    <element widget="form" slot="form">
        <xslot name="fields" />
    </element>
</view>

在这个视图中,我们可以获得如下信息:

  • 主视图为表单(FORM)视图。
  • 包含两个主要的element组件widget="actionBar"widget="form"

在我们内置的组件实现中,widget="form"这个组件通过调用后端接口,为整个视图提供数据源。

组件挂载时序图

image.png

``` mermaid
sequenceDiagram

participant FormView as FormView("view type=#quot;FORM#quot;")

participant ActionBar as ActionBarWidget("element widget=#quot;actionBar#quot;")

participant Form as FormWidget("element widget=#quot;form#quot;")

FormView ->> FormView : before mount
FormView ->> ActionBar : before mount
FormView ->> Form : before mount

ActionBar ->> FormView : mounted
Form ->> FormView : mounted
FormView ->> FormView : mounted

FormView ->> FormView : mountedCallChaing hook (VIEW_WIDGET_PRIORITY)

FormView ->> Form : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)

```

组件数据源加载

image.png

``` mermaid
sequenceDiagram

participant FormView as FormView("view type=#quot;FORM#quot;")

participant Form as FormWidget("element widget=#quot;form#quot;")

FormView ->> Form : mountedCallChaing hook (FETCH_DATA_WIDGET_PRIORITY)
Form ->> Form : mounted process (call api)
Form ->> FormView : reloadDataSource
Form ->> FormView : reloadActiveRecords

```

用户行为触发的数据交互

这里列举了一些对象(Object)常用的数据交互时序图,用于帮助大家对数据交互的整体逻辑可以有更清晰的理解。

点击提交动作(ServerAction)(创建/编辑)

image.png

``` mermaid
sequenceDiagram

participant FormView as FormView("view type=#quot;FORM#quot;")

participant Form as FormWidget("element widget=#quot;form#quot;")

participant ServerAction as ServerAction("action actionType=#quot;ServerAction#quot;")

ServerAction ->> FormView : submitCallChaining (call)
FormView ->> Form : submitCallChaining (call)
FormView ->> ServerAction : submitCallChaining (return)

ServerAction ->> ServerAction : execute action (call api)

```

Oinone社区 作者:oinone原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/26.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
oinone的头像oinone
上一篇 2023年6月20日 pm4:07
下一篇 2023年11月2日 pm1:58

相关推荐

  • 组件生命周期(v4)

    阅读之前: 你应该: 了解DSL相关内容。母版-布局-DSL 渲染基础(v4) 对第三方框架的组件生命周期有所了解。如Vue组件生命周期 了解平台实现的Class Component(ts)相关内容。Class Component(ts)(v4) 组件生命周期 任何一个Widget其标准生命周期应当包括beforeCreated、created、beforeMount、mounted、beforeUnmount、unmounted这六个基本的生命周期函数、以及beforeUpdate和updated在响应式更新时会进行调用的生命周期函数。特别的,还有activated和deactivated在组件搭配keep-alive特性时使用的生命周期函数。 具体的生命周期执行过程在这里不再进行赘述,这里的基本逻辑与Vue组件生命周期基本完全一致,感兴趣的读者可以阅读Vue相关文档进行学习。

    2023年11月1日
    1.3K10
  • 前端6.2.x升级指南

    升级背景 从 6.2.x 版本开始,平台底层核心代码已全面开源(设计器相关代码除外),本次升级涉及包名变更和配置调整,以下是详细的升级步骤 1. 更新 .npmrc 配置 修改当前项目根目录 .npmrc 文件,内容如下: registry=https://registry.npmmirror.com/ @oinone:registry=http://nexus.shushi.pro/repository/kunlun/ @kunlun:registry=http://nexus.shushi.pro/repository/kunlun/ shamefully-hoist=true legacy-peer-deps=true link-workspace-packages = true prefer-workspace-packages = true recursive-install = true lockfile=true 2. 包名变更 以前的包是 @kunlun/xxxx,现在的包名是@oinone/kunlun开头,所以需要全部替换修改。 旧包名 新包名 @kunlun/dependencies @oinone/kunlun-dependencies @kunlun/vue-ui-antd @oinone/kunlun-vue-ui-antd 3. 升级依赖版本 修改所有 package.json 中更新所有平台相关依赖: – "@kunlun/dependencies": "~5.7.0" + "@oinone/kunlun-dependencies": "~6.2.0" boot工程的package.json新增devDependencies依赖 "devDependencies": { "@types/lodash": "4.14.182", "@types/lodash-es": "4.17.6", ….. } 4. 更新代码引用 全局搜索并替换代码中的所有 @kunlun/ 为 @oinone/kunlun- 完整的 main.ts import 'ant-design-vue/dist/antd.min.css'; import 'element-plus/dist/index.css'; import '@oinone/kunlun-vue-ui-antd/dist/oinone-kunlun-vue-ui-antd.css'; import '@oinone/kunlun-vue-ui-el/dist/oinone-kunlun-vue-ui-el.css'; import '@oinone/kunlun-designer-common/dist/oinone-kunlun-designer-common.css'; import '@oinone/kunlun-model-designer/dist/oinone-kunlun-model-designer.css'; import '@oinone/kunlun-workflow-designer/dist/oinone-kunlun-workflow-designer.css'; import '@oinone/kunlun-workflow/dist/oinone-kunlun-workflow.css'; import '@oinone/kunlun-data-designer/dist/oinone-kunlun-data-designer.css'; import '@oinone/kunlun-microflow-designer/dist/oinone-kunlun-microflow-designer.css'; import 'reflect-metadata'; import ElementPlus from 'element-plus'; import { App } from 'vue'; import { VueOioProvider, RuntimeContextManager } from '@oinone/kunlun-dependencies'; // 设计器 import '@oinone/kunlun-ui-designer-dependencies'; import '@oinone/kunlun-print-designer-dependencies'; import '@oinone/kunlun-workflow'; import '@oinone/kunlun-workflow-designer'; import '@oinone/kunlun-model-designer'; import '@oinone/kunlun-data-designer'; import '@oinone/kunlun-data-designer-open-pc'; import '@oinone/kunlun-eip-dependencies'; import '@oinone/kunlun-ai-dependencies'; import '@oinone/kunlun-microflow-designer'; import '@oinone/kunlun-designer-common-ee'; // 下面三个依赖是当前工程的包,请根据实际场景修改 import '@ss/oinone'; import '@ss/admin-widget'; import '@ss/project'; VueOioProvider( { browser: { title: 'Oinone – 构你想象!', favicon: 'https://pamirs.oss-cn-hangzhou.aliyuncs.com/pamirs/image/default_favicon.ico' } }, [ () => { /// 获取当前vue实例 const app = RuntimeContextManager.createOrReplace().frameworkInstance as App; } ] ); 当配置全部修改完成后,重写安装依赖 # 清理旧依赖 pnpm clean # 安装新依赖 pnpm install

    2025年6月17日
    54100
  • 字段组件submit方法详解

    场景介绍 在日常开发调试表单页的过程中,细心的小伙伴应该注意到,视图内的数据(通过vue调试工具看到的formData就是视图的数据)和最终通过服务端动作提交的数据不总是一致的,本文将带领大家解开疑惑。 为什么会出现这种现象? 出现这种情况都是当前模型上有关联关系字段的场景,以多对一(M2O)场景为例,由于当前模型的关联关系字段是通过字段配置中的referenceFields属性和当前模型的relationFields属性进行关联的,所以提交数据的时候只需要拿到relationFields配置的字段就可以了,没有必要再去多拿关联关系字段本身的数据。 结合业务场景说明 这里以商品模型和类目模型举例,商品模型内有个类目的m2o字段category和对应的relationFields字段categoryId,数据提交到后端的时候前端默认会根据字段配置只获取categoryId,而category的整个对象都不会被提交。 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.demo.api.model.DemoItemCategory; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.common.CodeModel; @Model.model(DemoItem.MODEL_MODEL) @Model(displayName = "测试商品") public class DemoItem extends CodeModel { private static final long serialVersionUID = -5104390780952631397L; public static final String MODEL_MODEL = "demo.DemoItem"; @Field.String @Field(displayName = "商品名称") private String name; @Field.Integer @Field(displayName = "类目ID") private Long categoryId; @Field.many2one @Field.Relation(relationFields = {"categoryId"}, referenceFields = {"id"}) @Field(displayName = "商品类目") private DemoItemCategory category; } 前端是如何处理数据的 前端的字段组件提供了submit()方法来让我们可以有就会在提交数据的时候改变数据。 // 字段组件基类 export class BaseFormItemWidget< Value = unknown, Props extends BaseFormItemWidgetProps = BaseFormItemWidgetProps > extends BaseDataWidget<Props> { /** * 数据提交的方法,例如:m2o字段user(假设其关系字段为userId)的值{id: 1, name: 'xxx'},但是实际后端数据只需要其中的id,所以用m2o对应的关系字段userId提交数据就可以了 * @param submitValue */ public submit(submitValue: SubmitValue): ReturnPromise<Record<string, unknown> | SubmitRelationValue | undefined> { return undefined; } } 这里先以FormStringFieldSingleWidget组件处理密码类型的字段讲解。密码一般在输入的时候是明文,为了提高提交到后端的安全性,可以将这个密码加密后再传到后端,后端再做进一步处理,这个场景中,视图中的密码和提交给后端的密码就出现了不一致的情况, @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: [ViewType.Form, ViewType.Search], ttype: ModelFieldType.String }) ) export class FormStringFieldSingleWidget extends FormStringFieldWidget { public submit(submitValue: SubmitValue) { let finalValue = this.value; /** * 数据提交的时候,如果判断当前字段是否需要加密,需要加密的情况用encrypt函数做加密处理 */ if (this.crypto && finalValue) { finalValue = encrypt(finalValue); } return SubmitHandler.DEFAULT(this.field, this.itemName, submitValue, finalValue); } 注意:关系字段配置的透出字段只影响该字段的查询数据方法的返回值,不会因为此配置就在提交数据里加上这部分配置的字段 字段需要提交关联关系字段内的所有数据如何处理? 我们可以在自定义组件里覆写submit()方法,直接将this.value内的数据返回这里以覆写多对多m2m字段为例 import { BaseFieldWidget, FormM2MFieldSelectWidget, ModelFieldType, SPI, SubmitValue, ViewType } from '@kunlun/dependencies'; @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: ViewType.Form, ttype: ModelFieldType.ManyToMany, widget: 'Select', model: 'xxx.yyyyy', name: 'fileName01',…

    2024年9月10日
    1.4K00
  • oio-pagination 分页

    API 参数 说明 类型 默认值 版本 currentPage(v-model:currentPage) 当前页数 number – defaultPageSize 默认的每页条数 number 15 disabled 禁用分页 boolean – pageSize 每页条数 number – pageSizeOptions 指定每页可以显示多少条 string[] [’10’, ’15’, ’30’, ’50’, ‘100’, ‘200’] showQuickJumper 是否可以快速跳转至某页 boolean false showSizeChanger 是否展示 pageSize 切换器,当 total 大于 50 时默认为 true boolean – total 数据总数 number 0 事件 事件名称 说明 回调参数 change 页码或 pageSize 改变的回调,参数是改变后的页码及每页条数 Function(page, pageSize) noop

    2023年12月18日
    1.0K00
  • 表格主题配置(v4)

    TableThemeConfig /** * 表格主题配置 */ export interface TableThemeConfig { border: boolean | string; stripe: boolean; isCurrent: boolean; isHover: boolean; /** * 表格列主题配置 */ column: Partial<TableColumnThemeConfig>; } /** * 表格列主题配置 */ export interface TableColumnThemeConfig { /** * <h3>最小宽度</h3> * <ul> * <li>boolean: enabled column width auto compute</li> * <li>number: using css width (default: px)</li> * <li>string: using css width</li> * <li> * object: auto compute width for label by default function * <ul> * <li>min: min min width (default: 120)</li> * <li>max: max min width (default: 432)</li> * <li>chineseWidth: chinese width (default: 14 -> fontSize: 14px)</li> * <li>otherWidth: non chinese width (default: 9 -> fontSize: 14px)</li> * <li>sortableFixWidth: sortable handle width (default: 40)</li> * <li>nonSortableFixWidth: non sortable fix width (default: 22)</li> * </ul> * </li> * <li>function: auto compute width for label by function</li> * </ul> */ minWidth: boolean | number | string | Partial<TableColumnMinWidthComputeConfig> | TableColumnMinWidthComputeFunction; /** * 操作列 */ operation: { /** * 宽度 (default: 165) */ width?: number | string; /** * 最小宽度 (default: 120) */ minWidth?: number | string; }; } export interface TableColumnMinWidthComputeConfig { min: number;…

    2023年11月1日
    1.3K00

Leave a Reply

登录后才能评论