阅读之前
此文章为实战教程,已假定你熟悉了【界面设计器】较为完整的【自定义组件】相关内容。
如果在阅读过程中出现的部分概念无法理解,请自行学习相关内容。【前端】文章目录
业务背景
表格中的一列使用多个字段组合展示。
演示内容:表格中存在两列,【编码】和【基础信息】。将【名称】、【创建时间】、【更新时间】在【基础信息】一列展示。
业务分析及实现思路
从需求来看,我们需要实现一个【组合列】组件,并且该组件允许在【表格】视图中使用。由于【组合列】本身也是一个字段,因此这里需要选择需要组合字段中的其中一个字段作为组件切换的基础字段,比如我们可以选择【名称】字段作为基础字段。
在【组合列】组件的属性面板中,我们需要再自定义一个【组合列配置】组件,用来选择需要将哪些字段进行组合,以及为每个组合提供一些基础配置。
这里需要理解一个基本概念,即【组合列】的属性面板是【组合列配置】的【执行页面】。所有组件的属性面板在【执行页面】时都是【表单】视图。
因此我们可以实现一个【组合列配置】组件,并且该组件允许在【表单】视图中使用。其业务类型使用【文本】,我们在保存配置数据时,可以使用JSON
数据结构来存储复杂结构。(这里的实现思路并非是最符合协议设定的,但可以满足绝大多数组件场景)
在【组合列配置】组件中,我们可以允许用户添加/移除组合,并且每个组合有两个属性,【标题】和【字段】。
准备工作
此处你应该已经在某个业务模型下,可以完整执行当前模型的全部【增删改查】操作。
业务模型定义
(以下仅展示本文章用到的模型字段,忽略其他无关字段。)
名称 | API名称 | 业务类型 | 是否多值 | 长度(单值长度) |
---|---|---|---|---|
编码 | code | 文本 | 否 | 128 |
名称 | name | 文本 | 否 | 128 |
创建时间 | createDate | 日期时间 | 否 | - |
更新时间 | updateDate | 日期时间 | 否 | - |
实现页面效果展示
表格视图
创建组件、元件
准备工作完成后,我们需要根据【业务背景】确定【组件】以及【元件】相关信息,并在【界面设计器】中进行创建。
以下操作过程将省略详细步骤,仅展示可能需要确认的关键页面。
创建组合列组件
创建组合列元件
创建组合列配置组件
创建组合列配置元件
设计组合列元件属性面板
创建compositeConfig
字段,并切换至【组合配置】组件。
设计组合列配置元件属性面板
启动SDK工程进行组件基本功能开发
PS:这里由于我们创建了两个组件,因此,将SDK分开下载后,然后将组合列配置SDK
中的演示代码(kunlun-plugin/src)
移动到组合列SDK
中,在同一工程中进行开发,最后只需将相关JS文件
和CSS文件
上传到组合列
组件中即可,组合列配置
组件可以不进行上传。这里需要注意的是,上传多个包含相同组件功能的JS文件和CSS文件可能在运行时导致无法正常替换、冲突等问题。
(npm
相关操作请自行查看SDK工程中内置的README.MD
)
开发步骤参考
- 打开【表格】视图,将【名称】字段的组件切换为【组合列】组件。
- 在属性面板中看到【组合列配置】组件,并优先实现【组合列配置】组件。这里的属性面板就是【组合列配置】对应的【执行页面】。
- 当【组合列配置】组件可以按照预先设计的数据结构正确保存
compositeConfig
属性时,可以在【组合列】组件中的props
定义中直接获取该属性,接下来就可以进行【组合列】组件的开发。
代码实现参考
工程结构
typing.ts
export interface CompositeConfig {
key: string;
label?: string;
field?: string;
value?: string;
}
CompositeColumnConfig.vue
<template>
<div class="composite-column-config">
<oio-form v-for="item in list" :data="item" :key="item.key">
<oio-form-item label="标题" name="label">
<oio-input v-model:value="item.label" />
</oio-form-item>
<oio-form-item label="字段" name="field">
<a-select
class="oio-select"
dropdownClassName="oio-select-dropdown"
v-model:value="item.field"
:options="fields"
/>
</oio-form-item>
<oio-button type="link" @click="() => removeItem(item)">移除</oio-button>
</oio-form>
<oio-button type="primary" block @click="addItem">添加</oio-button>
</div>
</template>
<script lang="ts">
import { uniqueKeyGenerator } from '@kunlun/dependencies';
import { WidgetInstance } from '@kunlun/ui-designer-dependencies';
import { OioButton, OioForm, OioFormItem, OioInput } from '@kunlun/vue-ui-antd';
import { Select as ASelect } from 'ant-design-vue';
import { computed, defineComponent, PropType, ref, watch } from 'vue';
import { CompositeConfig } from '../../typing';
export default defineComponent({
name: 'CompositeColumnConfig',
components: {
OioForm,
OioFormItem,
OioInput,
OioButton,
ASelect
},
props: {
currentInstance: {
type: Object as PropType<WidgetInstance>
},
value: {
type: String
},
change: {
type: Function
}
},
setup(props) {
const list = ref<CompositeConfig[]>([]);
if (props.value) {
list.value = JSON.parse(props.value);
}
const addItem = () => {
list.value = [...list.value, { key: uniqueKeyGenerator() }];
};
const removeItem = (item: CompositeConfig) => {
const { key } = item;
if (!key) {
return;
}
const index = list.value.findIndex((v) => v.key === key);
if (index >= 0) {
list.value.splice(index, 1);
}
};
const fields = computed(() => {
return Array.from(props.currentInstance?.root?.fieldCollection.values() || []).map((v) => {
return {
label: v.element?.widgetData?.displayName,
value: v.element?.name
};
});
});
watch(
list,
(val) => {
props.change?.(JSON.stringify(val));
},
{ deep: true }
);
return {
list,
addItem,
removeItem,
fields
};
}
});
</script>
FormStringCompositeColumnConfigFieldWidget.ts
import { FormFieldWidget, ModelFieldType, SPI, ViewType, Widget } from '@kunlun/dependencies';
import { WidgetInstance } from '@kunlun/ui-designer-dependencies';
import CompositeColumnConfig from './CompositeColumnConfig.vue';
@SPI.ClassFactory(
FormFieldWidget.Token({
viewType: ViewType.Form,
ttype: ModelFieldType.String,
widget: 'CompositeColumnConfig',
multi: false
})
)
export class FormStringCompositeColumnConfigFieldWidget extends FormFieldWidget {
@Widget.Reactive()
@Widget.Inject()
protected currentInstance: WidgetInstance | undefined;
public initialize(props) {
super.initialize(props);
this.setComponent(CompositeColumnConfig);
return this;
}
}
CompositeColumn.vue(需新增文件)
<template>
<div class="composite-column-wrapper">
<div class="composite-field" v-for="item in fields" :key="item.key">
<span>{{ item.label }}</span>
<span class="composite-colon">:</span>
<span>{{ item.value }}</span>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { CompositeConfig } from '../../typing';
export default defineComponent({
name: 'CompositeColumn',
inheritAttrs: false,
props: {
fields: {
type: Array as PropType<CompositeConfig[]>
}
}
});
</script>
<style lang="scss">
.composite-column-wrapper {
display: flex;
flex-direction: column;
row-gap: 4px;
.composite-field {
& > .composite-colon {
margin-left: 2px;
margin-right: 4px;
}
}
}
</style>
TableStringCompositeColumnFieldWidget.ts
import {
BaseFieldWidget,
BaseTableFieldWidget,
ModelFieldType,
RowContext,
SPI,
ViewType,
Widget
} from '@kunlun/dependencies';
import { toString } from 'lodash-es';
import { createVNode, VNode } from 'vue';
import { CompositeConfig } from '../../typing';
import CompositeColumn from './CompositeColumn.vue';
@SPI.ClassFactory(
BaseFieldWidget.Token({
viewType: ViewType.Table,
ttype: ModelFieldType.String,
widget: 'CompositeColumn',
multi: false
})
)
export class TableStringCompositeColumnFieldWidget extends BaseTableFieldWidget {
@Widget.Reactive()
protected get compositeConfig(): CompositeConfig[] {
const { compositeConfig } = this.getDsl();
if (compositeConfig) {
return JSON.parse(compositeConfig);
}
return [];
}
protected getFields(context: RowContext) {
return this.compositeConfig
.filter((v) => !!v.field)
.map((v) => {
return {
...v,
value: toString(context.data[v.field!])
};
});
}
@Widget.Method()
public renderDefaultSlot(context: RowContext): VNode[] | string {
return [
createVNode(CompositeColumn, {
fields: this.getFields(context)
})
];
}
}
实现效果展示
配置组合列
表格展示
组合列属性面板
Oinone社区 作者:数式-海波原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/57.html
访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验