ZeroCloud 低代码开发平台
首页
用户手册
开发者手册
首页
用户手册
开发者手册
  • 用户手册

    • 产品简介
    • 快速入门
    • 工作台
    • 流程门户
    • 应用管理
    • 组织管理
    • 数据管理
    • 业务建模

      • 表单管理

        • 表单设计
        • 组件说明

          • 添加组件
          • 复制替换
          • 删除组件
        • 设置说明

          • 设置属性
          • 设置校验
          • 设置事件
        • 基础组件

          • 标题
          • 文字
          • 图片
          • 按钮
          • 链接
          • 分割线
          • 网页
        • 布局组件

          • 表单区块
          • 网格布局
          • 标签页
          • 明细表格
          • 明细区域
        • 功能组件

          • 输入文本
          • 日期时间
          • 单项选择
          • 多项选择
          • 下拉选择
          • 计数器
          • 开关
          • 滑块
          • 评分
          • 上传附件
          • 选择用户
          • 选择部门
          • 选择数据
          • 选择颜色
          • 富文本
          • UEditor
          • 条形码
          • 二维码
          • 添加明细行
          • 流程审批
          • 历史流程
      • 表单模型

        • 模型设计
        • 用法示例
      • 视图管理

        • 视图设计
        • 基础组件

          • 文字
          • 按钮
          • 图片
          • 链接
          • 分割线
          • 标签
          • 网页
          • Html
        • 布局组件

          • 页头
          • 容器
          • 网格
          • 区块
          • 卡片
          • 标签页
        • 模态组件

          • 对话框
          • 抽屉
        • 数据展示

          • 表格
          • 数据表格
          • 树
          • 数据树
          • 轮播图
          • 日历
          • 图表
          • 时间线
          • 步骤条
          • 宫格
          • 进度条
          • 分页
          • 标记
        • 数据输入

          • 表单/表单项
          • 文本框
          • 开关
          • 日期选择
          • 单项选择
          • 多项选择
          • 下拉选择
          • 滑块
          • 评分
      • 逻辑编排
      • 自定义组件
      • 报表管理
    • 流程设计

      • 流程定义

        • 流程设计
        • 节点配置
        • 办理人配置
      • 决策定义
      • 我的任务
      • 流程运维
      • 流程监控
    • 安全管理

      • 用户组
      • 安全角色
      • 权限资源
      • 权限分配
    • 系统监控

      • 系统监控
  • 开发者手册

    • 安装部署

      • 环境要求
      • 生产环境
    • 技术架构

      • 技术栈
    • API 文档

      • 概述
      • PC端 JS-API

        • 全局变量
        • PC表单
        • PC视图
      • 移动端 JS-API

        • 移动端
        • 移动表单
        • 移动视图
      • 服务端 API

        • 流程
        • 表单模型
        • 任务调度
        • 自定义服务
    • 常用案例

      • PC表单

        • 表单数据
        • 表单校验
        • 生命周期
        • 组件事件
        • 扩展方法
      • PC视图

      • 移动表单

      • 移动视图

      • 自定义服务

        • 写在案例之前
        • 环境搭建
        • Swagger 文档
        • 前台通用请求方式
        • 自定义返回值
        • ajax 参数
        • 按钮点击给明细表赋值
        • 表单展示接口报错
        • 数据选择使用ajax
        • 数据源使用后台接口
        • 根据临时变量的值给后台传参
        • 批量删除
        • 删除按钮
        • 入库判断库存
        • 表单调用后台自定义接口
        • 后台发起流程
        • 出库校验
        • 视图调用后台自定义接口
  • 视频教程

    • 培训视频

      • 2024-08-30
  • 常见问题

    • 问题反馈

自定义组件

自定义组件用于对表单设计器基础组件的拓展,此功能基于 vue 开发,使用自定义组件需要对 vue 技术有一定的了解。

本文以 luckysheet 为例,开发一个自定义组件。

luckysheet官网

一.引入依赖

首先找到组件库管理页面

设置完基本信息后点击组件依赖项,新建依赖

然后找到官网 luckysheet 的依赖,将其添加到组件库依赖中,此处需要注意引入的js文件只能为umd格式,样式文件只能是css。添加依赖的方式有两种

1.CDN引入

将依赖CDN粘贴到依赖URL中即可,注意使用CDN引入时需要连接外网

<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css' />
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js"></script>

2.本地引入

将所需依赖打包放至根目录 public/lib 文件夹下,使用相对路径写入到依赖URL中,建议此方法引入

二.设计组件

打开代码编辑器,找到 src/components 文件夹,新建 zc-custom-luckysheet 文件夹,在 zc-custom-luckysheet文件夹下新建 src 文件夹用于放置组件主体代码 index.vue 和组件属性编辑代码 attrs-panel.vue ,并且新建index.js 用于导出组件

1.组件设计器

打开 index.vue 文件,在编辑器中加入如下模板

<template>
  <div class="zc-custom-luckysheet">
    <el-form-item
      class="zc-custom-luckysheet"
      :label="label"
      :prop="zcAsyncValidatorProp"
      :rules="zcAsyncValidatorRules"
    >
    <!-- 组件设计区域 -->
    </el-form-item>
    <!-- 其他区域 -->
  </div>
</template>

<script>
import ZcFormElement from 'zerocloud-form-core/src/components/zc-form-element'
export default {
  name: 'zc-custom-luckysheet',
  extends: ZcFormElement,
  data(){
        return{}
    },
  mounted(){},
  methods:{}
}
</script>

<style lang="scss" scoped>

</style>

el-form-item 标签内放置需要展示的组件代码,标签外放置与组件展示无关的代码,例如 dialog 弹出框、Notification 通知等

ZcFormElement 为表单设计器的基础类,封装有表单的基础属性,以下列举几种常用属性,更多了解请查看源码

  • label:表单项左侧标签名称
  • zcAsyncValidatorProp:表单验证的字段名
  • zcAsyncValidatorRules:表单验证的规则
  • zcDesignMode:设计模式,用于区分表单设计模式和预览/生产模式
  • zcValue:组件绑定字段数据
  • $attrs:组件的基础数据

根据 luckysheet 官网教程初始化表格

添加表格容器

    <el-form-item
      class="zc-custom-luckysheet"
      :label="label"
      :prop="zcAsyncValidatorProp"
      :rules="zcAsyncValidatorRules"
    >
      <!-- luckysheet表格容器 -->
      <div class="container" v-if="!zcDesignMode" :style="{ width: $attrs.width, height: $attrs.height } >
        <div id="luckysheet" class="luckysheet" :style="{ width: $attrs.width, height: $attrs.height }></div>
      </div>
      <div class="empty" v-else>luckysheet</div>
    </el-form-item>

添加初始化数据、方法

	data(){
        return{
		  // luckysheet 表格参数
		  options: {
        	  name: 'Cell', //工作表名称
        	  lang: 'zh',
        	  container: 'luckysheet', // 容器id
        	  data: [
          			  {
            			name: 'Cell', //工作表名称
            			color: '', //工作表颜色
            			index: 0, //工作表索引
            			status: 1, //激活状态
            			order: 0, //工作表的下标
            		    hide: 0, //是否隐藏
            			row: 100, //行数
            			column: 50, //列数
            			defaultRowHeight: 30, //自定义行高
            			defaultColWidth: 100, //自定义列宽
            			celldata: [],
          			  },
        			],
      			},
			}
    },
	mounted(){
		this.init() // 初始化vue页面完成后调用初始化 luckysheet 函数
	},
  	methods:{
		init(){
			if(this.zcDesignMode) return
			luckysheet.create(this.options) // 初始化 luckysheet 
		}
	}

由于 luckysheet 操作的是dom,同一设计页面不能出现多个 luckysheet 容器,而设计页面和预览页面是属于一个 vue 页面的,所以在此初始化时进行判断,只有在预览时初始化,设计界面不予展示

添加样式,因为 luckysheet 默认样式为 absolute ,所以父容器必须设置属性 position: relative

<style lang="scss" scoped>
.container {
  position: relative;
}
</style>

2.组件属性编辑器

打开 attrs-panel.vue 文件,在编辑器中加入如下模板

<!--luckysheet属性编辑器-->
<template>
	<div class="zc-custom-luckysheet-attrs-panel">
		<el-form v-if="currentComp" v-bind="compAttrsFormConfig">
			<el-form-item label="宽度">
				<el-input v-model="currentComp.attrs.width" placeholder="px"></el-input>
			</el-form-item>
			<el-form-item label="高度">
				<el-input v-model="currentComp.attrs.height" placeholder="px"></el-input>
			</el-form-item>
		</el-form>
	</div>
</template>

<script>
import lodash from 'lodash'
import ZcFormDesignerStoreMixin from 'zerocloud-form-designer-core/src/mixins/designer-store-mixin.js'

export default {
	name: 'zc-custom-luckysheet-attrs-panel',
	mixins: [
		ZcFormDesignerStoreMixin
	],
	components: {},
	data() {
		return {}
	},
	methods: {}
}
</script>

此模板是基于 element ui 中的 form 表单进行的数据绑定,但是开发者在实际开发中可以不局限于此种形式,只要可以进行数据的改动,即可实现对属性的编辑

ZcFormDesignerStoreMixin 是组件属性编辑器的混入类,封装有表单的基础属性

currentComp为此组件绑定的数据

    {
        "tag": "zc-custom-luckysheet", // 组件标志
        "name": "luckysheet", // 组件名称
        "icon": "el-icon-data-line", // 组件图表
        "attrs": { // 组件基础信息
            "label": "表格",
            "width": "800px",
            "height": "500px"
        },
        "zcAttrs": { // ZeroCloud平台数据,用于数据绑定、数据映射等
            "databind": null
        }
    }

在此处更改的数据可以同步更新到 index.vue 中,用于设计组件的属性、样式等

3.导出组件

打开 index.js 文件,在编辑器中加入如下模板

import ZcCustomLuckysheet from './src/index.vue'

ZcCustomLuckysheet.install = function (Vue) {
    Vue.component(ZcCustomLuckysheet.name, ZcCustomLuckysheet)
}

export default ZcCustomLuckysheet

打开 src 根目录下的 index.js 文件,根据模板导入组件设计器和属性编辑器

import ZcCustomAutograph from './components/zc-custom-autograph/src/index.vue'
import ZcCustomAutographAttrsPanel from './components/zc-custom-autograph/src/attrs-panel.vue'

import ZcCustomLuckysheet from './components/zc-custom-luckysheet/src/index.vue'
import ZcCustomLuckysheetAttrsPanel from './components/zc-custom-luckysheet/src/attrs-panel.vue'

const components = [ ZcCustomAutograph , ZcCustomLuckysheet ]

const attrsPanels = [ ZcCustomAutographAttrsPanel , ZcCustomLuckysheetAttrsPanel ]

const install = function (Vue) {
  if (install.installed) return
  components.map((component) => Vue.component(component.name, component))
  attrsPanels.map((component) => Vue.component(component.name, component))
}

if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}

let componentsMap = {}
components.forEach((component) => {
  componentsMap[component.name] = component
})

let attrsPanelsMap = {}
attrsPanels.forEach((component) => {
  attrsPanelsMap[component.name] = component
})

export default {
  install,
  componentsMap,
  attrsPanelsMap,
}

三.组件定义

打开组件库,组件定义选项,将上述属性编辑器中的 currentComp 写入数组中,点击保存即可完成自定义组件的基础搭建

进入到表单设计器中即可发现新建的组件库与自定义的组件

点击预览,可以看到 luckysheet 初始化成功

四.数据交互

以上步骤完成了自定义组件基础框架的搭建,但是仅仅展示一个页面是远远不够的,所以在自定义组件模块中也嵌入了 ZeroCloud 平台的数据交互模块

1.配置数据源

在 attrs-panel.vue 文件中导入数据源组件、添加数据源方法,并且将组件添加到页面中(此处仅展示数据源相关代码)


<template>
	<div class="zc-custom-luckysheet-attrs-panel">
        <el-form>
        	<el-form-item label="数据源">
				<el-button icon="el-icon-zc-data" style="width:100%" @click="editDataSource">配置数据源</el-button>
			</el-form-item>
		</el-form>
        <!-- 数据源组件 -->
		<DataSourceConfigDrawer :visible.sync="datasourceDlg.visible" :model="datasourceDlg.model" @confirm="saveDataSource" />
        
	</div>
</template>
<script>
    
import DataSourceConfigDrawer from 'zerocloud-form-designer-core/src/components/dialogs/datasource/datasource-config-drawer.vue'

export default {
	components: {
		DataSourceConfigDrawer,
	},
	data() {
		return {
			// 数据源对话框
			datasourceDlg: {
				visible: false,
				model: null
			}
		}
	},
	methods: {
		// 编辑数据源
		editDataSource() {

			this.datasourceDlg.model = this.currentComp.zcAttrs.datasource;
			this.datasourceDlg.visible = true;
		},

		// 保存数据源回调
		saveDataSource(dsModel) {

			// 判断数据源是否更改,若已更改,则清空数据映射
			let srcModel = lodash.cloneDeep(this.currentComp.zcAttrs.datasource);
			let modified = this.isDataSourceModified(srcModel, dsModel);
			if (modified) {
				this.$set(this.currentComp.zcAttrs, 'datamap', []);
			}

			this.$set(this.currentComp.zcAttrs, 'datasource', lodash.cloneDeep(dsModel));
		}
	}
}
</script>

此时表单设计器中组件属性可以看到编辑数据源按钮,点击即可配置绑定数据源

打开 index.vue ,进行数据选取的配置操作(此处仅展示数据选取相关代码)

<template>
  <div class="zc-custom-luckysheet">
    <el-form-item
      class="zc-custom-luckysheet"
      :label="label"
      :prop="zcAsyncValidatorProp"
      :rules="zcAsyncValidatorRules"
    >
      <el-button @click="openDialog"> 选择数据 </el-button>
    </el-form-item>

    <el-dialog
      :visible.sync="dataDlg.visible"
      title="自定义数据"
      append-to-body
      @close="cancel"
    >
      <el-table
        ref="table"
        :data="page.rows"
        @selection-change="onSelectionChange"
      >
        <el-table-column
          type="selection"
          width="50px"
          align="center"
        ></el-table-column>
        <el-table-column type="index" label="序号"></el-table-column>
        <el-table-column label="编号" prop="MaterialCode"></el-table-column>
        <el-table-column label="名称" prop="MaterialName"></el-table-column>
        <el-table-column label="价格" prop="MaterialPrice"></el-table-column>
      </el-table>
      <div style="text-align: center">
        <el-pagination
          layout="total, sizes, prev, pager, next, jumper"
          :current-page.sync="page.index"
          :page-size.sync="page.size"
          :total="page.total"
          :page-sizes="[10, 20, 50]"
          @current-change="loadData()"
          @size-change="loadData()"
        ></el-pagination>
      </div>
      <div slot="footer">
        <el-button type="primary" @click="confirm">确认</el-button>
        <el-button @click="cancel">关闭</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dataDlg: {
        visible: false,
      },

      keyword: null,

      page: {
        index: 1,
        size: 10,
        rows: [],
      },

      selectedRows: [],
    }
  },
  computed: {
    // 数据源
    zcDataSource() {

      return this.zcAttrs.datasource
    },
  },
  watch: {
    'dataDlg.visible'(val) {

      if (val) {
        this.loadData()
      } else {
        this.page.index = 1
        this.page.rows = []
      }
    },
  },
  methods: {
    // 加载数据
    loadData() {

      let index = this.page.index
      let size = this.page.size

      // 常量
      const consts = {
        page: {
          keyword: this.keyword == null ? `''` : `'${this.keyword}'`,
          index: index,
          size: size,
        },
      }


      if (!this.zcDataSource) return

      let datasource = lodash.cloneDeep(this.zcDataSource)

      // 系统数据源
      if (datasource.type == 'sysDataSource') {
        let dsConfig = datasource.config
        let ds = dsConfig.ds
        let objType = dsConfig.objType
        let objName = dsConfig.objName
        let objConfig = dsConfig.objConfig

        // 表/视图
        if (objType == 'tableview') {
          let pageSearchConfig = {
            index,
            size,
            keyword: this.keyword,
            sorters: this.sorters,
            filters: {
              op: 'and',
              rules: [],
              groups: [
                lodash.cloneDeep(this.filters),
                lodash.cloneDeep(objConfig.filters),
              ],
            },
          }

          pageSearchConfig.filters = this.loadData_convertExpFilterGroupValue(
            pageSearchConfig.filters
          )
          pageSearchConfig.filters = this.fillFilterGroupValues(
            pageSearchConfig.filters,
            consts
          )

          this.loading = true

          this.zcDsManagerInst
            .sysDs_getTableviewPageData(ds, objName, pageSearchConfig)
            .then((data) => {
              console.log('data', data)
              this.loading = false
              let result = { ...data }
              result.total = +result.total
              this.page = result
              console.log('this.page', this.page)
            })
            .catch((err) => {
              this.loading = false
            })
        }
      }
    },

    loadData_convertExpFilterGroupValue(filterGroup) {

      if (!filterGroup) {
        return {
          op: 'and',
          rules: [],
          groups: [],
        }
      }

      let rules = filterGroup.rules || []
      rules.forEach((r) => {
        if (isNaN(parseFloat(r.v))) {
          r.v = `"${r.v}"`
        }
      })

      let groups = filterGroup.groups || []
      groups.forEach((g, gIndex) => {
        groups[gIndex] = this.loadData_convertExpFilterGroupValue(g)
      })

      return filterGroup
    },

    // 勾选表格行
    onSelectionChange(selection) {

      this.selectedRows = [...selection]
    },

    openDialog() {

      this.dataDlg.visible = true
    },

    confirm() {
      let selection = this.selectedRows || []

      if (!selection || selection.length == 0) return

      this.mapData(selection)
      this.cancel()
    },

    cancel() {
      this.dataDlg.visible = false
    }
  }
}
</script>

只需在 loadData 方法中传入 page 配置项即可获取数据,此处使用了 element ui 的 table 表格组件进行数据展示,但是开发者在实际开发中可以不局限于此种形式。当用户选择完数据点击确定后,所选择数据便被储存到selectedRows 内

开发者可以根据选中数据对组件进行交互,例如将所选数据展示到 luckysheet 表格中

在 methods 中添加setData方法,并且在点击确定的方法中调用此方法

confirm() {
	......
     this.setData()
    },
setData() {

      let selection = this.selectedRows || []

      let celldata = []

      // 表头
      let i = 0
      for (let key in selection[0]) {
        let cell = {
          r: 0,
          c: i,
          v: {
            ct: { fa: 'General', t: 'g' },
            m: key,
            v: key,
          },
        }
        celldata.push(cell)
        i++
      }

      // 表体
      selection.forEach((row, index) => {
        let k = 0
        for (let key in row) {
          let cell = {
            r: index + 1,
            c: k,
            v: {
              ct: { fa: 'General', t: 'g' },
              m: row[key],
              v: row[key],
            },
          }
          celldata.push(cell)
          k++
        }
      })

      luckysheet.destroy()
      this.$nextTick(() => {
        this.options.data[0].celldata = celldata // 初始化数据
        delete this.options.data[0].data // 初始化后lucky sheet使用数据,必须清空,不然不会渲染celldata

        luckysheet.create(this.options)
      })
    },

选取数据后即可渲染至表格

2.数据映射(此功能需要先配置数据源)

在 attrs-panel.vue 文件中导入数据映射组件、添加数据映射方法,并且将组件添加到页面中(此处仅展示数据映射相关代码)

<!--luckysheet属性编辑器-->
<template>
	<div class="zc-custom-luckysheet-attrs-panel">
		<el-form v-if="currentComp" v-bind="compAttrsFormConfig">

			<el-form-item label="数据映射">
				<el-button :icon="loadingDsSchema ? 'el-icon-loading' : 'el-icon-zc-datamap'" :disabled="loadingDsSchema" style="width:100%" @click="editDatamap">编辑映射</el-button>
			</el-form-item>

		</el-form>

		<DatamapDrawer :visible.sync="datamapDlg.visible" :fields="datamapDlg.fields" :rules="datamapDlg.rules" @confirm="saveDatamap" />
	</div>
</template>

<script>

import DatamapDrawer from 'zerocloud-form-designer-core/src/components/dialogs/datamap/datamap-drawer.vue'
    
export default {

	components: { DatamapDrawer },
	data() {
		return {	
			// 数据映射对话框
			datamapDlg: {
				visible: false,
				rules: [],
				fields: []
			},
		}
	},
	methods: {
		// 编辑数据映射
		editDatamap() {

			this.datamapDlg.rules = this.currentComp.zcAttrs.datamap;
			this.datamapDlg.fields = this.dsSchema.map(item => {
				return {
					label: item.name,
					value: item.name
				};
			});
			this.datamapDlg.visible = true;
		},

		// 保存数据映射
		saveDatamap(rules) {

			this.$set(this.currentComp.zcAttrs, 'datamap', rules);
		}
	}
}
</script>

此时表单设计器中组件属性可以看到编辑映射按钮,点击即可配置数据映射

3.编辑选项(用于单选、多选、下拉等 label、value形式的数据选择)

由于此模块不适用于 luckysheet 组件,故新建 zc-custom-checkbox 自定义组件用于展示,新建过程不在赘述,具体内容请参考上述文档说明。注意,此组件是基于 element ui 的 checkbox 组件自定义的,而系统内已经内置了element ui 的依赖,所以不需要额外的导入依赖

Prev
逻辑编排
Next
报表管理